User tests: Successful: Unsuccessful:
Pull Request resolves #48034.
updateManifestCaches() in administrator/components/com_admin/script.php queries every core extension (by type/element/folder/client_id) and calls Installer::refreshManifestCache() on each, reporting a "Error on updating manifest cache" message for any that return false.
Installer::refreshManifestCache() deliberately aborts and returns false when an extension's state == -1 (its own translated message, JLIB_INSTALLER_ABORT_REFRESH_MANIFEST_CACHE, exists specifically for this) — that's intentional, not a real failure. But updateManifestCaches() has no way to tell an intentional no-op from a genuine problem, so any core extension that ends up at state = -1 (as the reporter saw for phpass and plg_quickicon_eos after a 3.x → 6.1.1 migration) always surfaces a spurious error during every subsequent update or reinstall.
A state = -1 extension is not "disabled" — that's a separate enabled column. state = -1 is set by the discover() method of the installer adapters (e.g. ComponentAdapter::discover()) for old core files that are present on disk but not registered in the #__extensions table — typically leftovers from a core extension that wasn't cleanly removed during a previous update, or restored from an old backup. It's cleared to 0 only once the discovered extension is actually installed via prepareDiscoverInstall().
Added state != -1 to the query's per-extension WHERE clause, so these discovered-but-unregistered core extensions are excluded from the refresh attempt entirely instead of being attempted and then reported as failed. This doesn't touch Installer::refreshManifestCache() itself or try to address why a core extension ends up at state=-1 after a migration — that's a separate question about the upgrade/discovery path; this only stops a known no-op from being reported as an error.
Tested with a real Joomla installation and complete Joomla core updates (not just code review):
5.4-dev, commit 0ec52b315b5.4.9-dev+pr.48446, commit e4daeff3f0Use a disposable Joomla 5.4-dev installation or two identical copies of one installation. Replace j54_ below with your site's database prefix.
SELECT extension_id, name, type, element, folder, client_id, state
FROM j54_extensions
WHERE type = 'library'
AND element IN ('joomla', 'phpass')
ORDER BY extension_id;UPDATE j54_extensions
SET state = -1,
manifest_cache = 'DISABLED_SENTINEL'
WHERE type = 'library'
AND element = 'phpass'
AND folder = ''
AND client_id = 0;
UPDATE j54_extensions
SET manifest_cache = 'ACTIVE_SENTINEL'
WHERE type = 'library'
AND element = 'joomla'
AND folder = ''
AND client_id = 0;php cli/joomla.php core:update:channel custom \
--url='https://artifacts.joomla.org/drone/joomla/joomla-cms/5.4-dev/48450/downloads/96430/pr_list.xml' \
--no-interaction
php cli/joomla.php core:update:check --no-interaction
php cli/joomla.php core:update --no-interaction --no-ansiAlternatively, use System → Update → Joomla with that custom update URL.
[ERROR] Update finished with errors. Please check logs for details.
The update log contained:
Refresh Manifest Cache failed: lib_phpass Extension is not currently installed.
An error has occurred while running "JoomlaInstallerScript::updateManifestCaches". Code: 0. Message: Error on updating manifest cache: (type, element, folder, client) = (library, phpass, lib_phpass, 0).
Restore the original disposable installation/database snapshot, or repeat on the second identical installation. Run the two SQL UPDATE statements again.
Configure Joomla to use this PR's official update package instead, and repeat the update:
php cli/joomla.php core:update:channel custom \
--url='https://artifacts.joomla.org/drone/joomla/joomla-cms/5.4-dev/48446/downloads/96422/pr_list.xml' \
--no-interaction
php cli/joomla.php core:update:check --no-interaction
php cli/joomla.php core:update --no-interaction --no-ansiThe same operation can be run from System → Update → Joomla after setting the custom update URL in the Joomla Update options.
[OK] Joomla core updated successfully!
There should be no updateManifestCaches/lib_phpass error.
SELECT
extension_id,
name,
element,
state,
manifest_cache = 'DISABLED_SENTINEL' AS disabled_sentinel_unchanged,
manifest_cache = 'ACTIVE_SENTINEL' AS active_sentinel_unchanged,
JSON_VALID(manifest_cache) AS valid_manifest_json,
JSON_UNQUOTE(JSON_EXTRACT(manifest_cache, '$.version')) AS manifest_version
FROM j54_extensions
WHERE type = 'library'
AND element IN ('joomla', 'phpass')
ORDER BY extension_id;My result after applying the PR was:
lib_joomla state=0 active_sentinel_unchanged=0 valid_manifest_json=1 manifest_version=13.1
lib_phpass state=-1 disabled_sentinel_unchanged=1 valid_manifest_json=0
This confirms that the state=-1 extension was excluded while the normal core extension still had its manifest cache refreshed.
Any core extension sitting at state = -1 causes updateManifestCaches() to report an "Error on updating manifest cache" during every subsequent Joomla core update or reinstall, even though the extension was correctly and intentionally skipped.
Core extensions with state = -1 are excluded from the refresh query entirely, so they no longer produce a spurious error during updates.
Please select:
Documentation link for guide.joomla.org:
No documentation changes for guide.joomla.org needed
Pull Request link for manual.joomla.org:
No documentation changes for manual.joomla.org needed
| Status | New | ⇒ | Pending |
| Category | ⇒ | Administration com_admin |
I have now tested this with a real Joomla installation and complete Joomla core updates, rather than relying on code review.
5.4-dev, commit 0ec52b315b5.4.9-dev+pr.48446, commit e4daeff3f0Use a disposable Joomla 5.4-dev installation or two identical copies of one installation. Replace j54_ below with your site's database prefix.
SELECT extension_id, name, type, element, folder, client_id, state
FROM j54_extensions
WHERE type = 'library'
AND element IN ('joomla', 'phpass')
ORDER BY extension_id;UPDATE j54_extensions
SET state = -1,
manifest_cache = 'DISABLED_SENTINEL'
WHERE type = 'library'
AND element = 'phpass'
AND folder = ''
AND client_id = 0;
UPDATE j54_extensions
SET manifest_cache = 'ACTIVE_SENTINEL'
WHERE type = 'library'
AND element = 'joomla'
AND folder = ''
AND client_id = 0;For a reproducible 5.4-dev control, I used Joomla CI's unrelated PR 48450 package, which does not contain this fix:
php cli/joomla.php core:update:channel custom \
--url='https://artifacts.joomla.org/drone/joomla/joomla-cms/5.4-dev/48450/downloads/96430/pr_list.xml' \
--no-interaction
php cli/joomla.php core:update:check --no-interaction
php cli/joomla.php core:update --no-interaction --no-ansiAlternatively, use System → Update → Joomla with that custom update URL.
[ERROR] Update finished with errors. Please check logs for details.
The update log contained:
Refresh Manifest Cache failed: lib_phpass Extension is not currently installed.
An error has occurred while running "JoomlaInstallerScript::updateManifestCaches". Code: 0. Message: Error on updating manifest cache: (type, element, folder, client) = (library, phpass, lib_phpass, 0).
Restore the original disposable installation/database snapshot, or repeat on the second identical installation. Run the two SQL UPDATE statements again.
Configure Joomla to use this PR's official update package:
php cli/joomla.php core:update:channel custom \
--url='https://artifacts.joomla.org/drone/joomla/joomla-cms/5.4-dev/48446/downloads/96422/pr_list.xml' \
--no-interaction
php cli/joomla.php core:update:check --no-interaction
php cli/joomla.php core:update --no-interaction --no-ansiThe same operation can be run from System → Update → Joomla after setting the custom update URL in the Joomla Update options.
[OK] Joomla core updated successfully!
There should be no updateManifestCaches/lib_phpass error.
SELECT
extension_id,
name,
element,
state,
manifest_cache = 'DISABLED_SENTINEL' AS disabled_sentinel_unchanged,
manifest_cache = 'ACTIVE_SENTINEL' AS active_sentinel_unchanged,
JSON_VALID(manifest_cache) AS valid_manifest_json,
JSON_UNQUOTE(JSON_EXTRACT(manifest_cache, '$.version')) AS manifest_version
FROM j54_extensions
WHERE type = 'library'
AND element IN ('joomla', 'phpass')
ORDER BY extension_id;My result after applying the PR was:
lib_joomla state=0 active_sentinel_unchanged=0 valid_manifest_json=1 manifest_version=13.1
lib_phpass state=-1 disabled_sentinel_unchanged=1 valid_manifest_json=0
This confirms that the state=-1 extension was excluded while the normal core extension still had its manifest cache refreshed.
| Labels |
Added:
PR-5.4-dev
|
||
Surely the correct approach is to determine why/how those extensions were able to get a state of -1 which should not be possible
I have now tested this with a real Joomla installation and complete Joomla core updates, rather than relying on code review.
Testing instructions
@wakqasahmed I've asked you to update the testing instructions in the PR description (initial post) so other testers can find them.
Surely the correct approach is to determine why/how those extensions were able to get a state of -1 which should not be possible
A state of -1 is set for extensions in the discover methods of the diverse installer adapters, e.g. for components here: https://github.com/joomla/joomla-cms/blob/5.4-dev/libraries/src/Installer/Adapter/ComponentAdapter.php#L1279
Later, when installing the discovered extensions, the state is set to zero before trying to store the database record in the extensions table in methods https://github.com/joomla/joomla-cms/blob/5.4-dev/libraries/src/Installer/Adapter/ComponentAdapter.php#L1279 of the installer adapters, e.g. for components here: https://github.com/joomla/joomla-cms/blob/5.4-dev/libraries/src/Installer/Adapter/ComponentAdapter.php#L639
So a state of -1 happens for old core extensions which were not properly uninstalled during a previous core update, or they have been properly uninstalled but later an old backup was restored where the files still were present, so the extension discovery has found them.
Now the question for this PR here is do we want to skip these extension when doing the update, like suggested by this PR?
Surely the correct approach is to determine why/how those extensions were able to get a state of -1 which should not be possible
A state of -1 is set for extensions in the discover methods of the diverse installer adapters, e.g. for components here: https://github.com/joomla/joomla-cms/blob/5.4-dev/libraries/src/Installer/Adapter/ComponentAdapter.php#L1279
Later, when installing the discovered extensions, the state is set to zero before trying to store the database record in the extensions table in methods prepareDiscoverInstall of the installer adapters, e.g. for components here: https://github.com/joomla/joomla-cms/blob/5.4-dev/libraries/src/Installer/Adapter/ComponentAdapter.php#L639
So a state of -1 happens for old core extensions which were not properly uninstalled during a previous core update, or they have been properly uninstalled but later an old backup was restored where the files still were present, so the extension discovery has found them.
Now the question for this PR here is do we want to skip these extension when doing the update, like suggested by this PR?
Thanks for digging into the discover/prepareDiscoverInstall path — that matches what I saw for phpass/plg_quickicon_eos after the migration. My take: yes, skipping them in the refresh query seems like the safer near-term fix regardless of how they got to state=-1 in the first place, since refreshManifestCache() already treats that state as an intentional no-op elsewhere. Happy to adjust the approach if the team decides the real fix belongs in the discovery/migration path instead.
@wakqasahmed So or so the title "Skip disabled core extensions ..." of your PR is wrong, the extensions are not disabled, they are discovered. The disabled states is in another database column (enabled).
And you still haven't added useful testing instructions for human testers to the description (initial post) of your PR so testers can find them. They will not find them buried in the comment thread of this PR.
I have asked before 2 times to do that.
| Title |
|
||||||
@richard67 Both addressed:
Title: Fixed. Old title said "Skip disabled core extensions ..."; new title is "[AI] Skip discovered core extensions in updateManifestCaches() (#48034)". You're right that state = -1 isn't the enabled column — I confirmed it's set by the installer adapters' discover() methods (e.g. ComponentAdapter::discover(), line 1297) for old core files present on disk but not registered in #__extensions, and only cleared once the discovered extension is actually installed via prepareDiscoverInstall(). Updated the PR description to explain this distinction as well.
Testing instructions: Moved into the PR description (initial post) under "Testing Instructions", including the environment details, the SQL setup/verification steps, and the before/after core-update commands and results from my comment above. They're no longer only in the comment thread.
Thanks for the pointers on the discover/prepareDiscoverInstall path — that context is now reflected in the Summary of Changes too.
Hi @richard67 @HLeithner — noticed this PR doesn't have a reviewer assigned yet — it's been sitting for a while, CI is green and it's mergeable. Would you (or whoever's best placed) be able to take a look, or point me to who should? Thanks!
@wakqasahmed Thank you for your contribution!
The Joomla bug-fixing process requires two successful human tests by people other than the contributor, documented in the issue tracker, before we can consider merging the PR.
A code review is independent of that process, and we usually don't assign reviewers to pull requests.
As we are all volunteers, getting enough testers can sometimes take a while. Helping hands are always welcome — perhaps you could also help by testing some other pull requests 🙏 That would be greatly appreciated!
Hi @richard67 @muhme — circling back on this one — still no reviewer assigned, quiet for a while since the last activity. No pressure, just don't want it to get lost.
Hi @richard67 @muhme — circling back on this one — still no reviewer assigned, quiet for a while since the last activity. No pressure, just don't want it to get lost.
@wakqasahmed Every PR needs 2 successful tests by humans, and this has to be carried out by volunteers. Of course if all volunteers propose PRs but (almost) nobody of them tests other people's PRs, then we have a backlog.
Keeping maintainers and release managers busy with such "reminders" doesn't help the project either.
This pull request has been automatically rebased to 6.2-dev. Joomla! 5.4 is now in security only mode.
| Title |
|
||||||
@wakqasahmed A code review is definitely not a sufficient test. It needs to do a real test with a cure update.
Things which are relevant for end users have to be tested with real human tests.
In addition, we require that contributors have tested their PRs themselves before submitting. Your testing instructions read as if you have not done such a real test and relied on code review (with help of AI). So this requirements seems not to be fulfilled either.
Please provide useful testing instructions for end users for other testers and test your changes with these instructions, too.
Thanks in advance.