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.
Added state != -1 to the query's per-extension WHERE clause, so disabled/pending-removal 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 path; this only stops a known no-op from being reported as an error.
No existing test harness covers this script (it's a legacy install/update hook with no unit tests, and a full behavioral test would need a DB-backed core-update simulation). Verified manually: with the query's OR-joined per-extension clauses, AND state != -1 is appended inside each extension's own AND-chain, so it's scoped correctly per extension regardless of the other extensions in the list (SQL AND binds tighter than OR, and Joomla's QueryElement doesn't wrap each where() call in its own parentheses, so this only works because of that precedence — confirmed by reading Joomla\Database\Query\QueryElement::__toString()). Also confirmed against a fixture list of (extension_id, state) pairs that state=-1 rows are excluded from the result set while state 0/1 rows remain.
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.
@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.