Problem/Motivation
When updating the DB after an update from 8.8.5 to 8.8.1 the following error occurred:
The website encountered an unexpected error. Please try again later.
Drupal\Core\Extension\Exception\UnknownExtensionException: The module mymodule does not exist. in Drupal\Core\Extension\ExtensionList->get() (line 265 of core/lib/Drupal/Core/Extension/ExtensionList.php).
Drupal\Core\Extension\ExtensionList->get('mymodule') (Line: 579)
Drupal\Core\Extension\ExtensionList->checkIncompatibility('chosen') (Line: 318)
update_get_update_list() (Line: 272)
Drupal\system\Controller\DbUpdateController->selection(Object) (Line: 163)
Drupal\system\Controller\DbUpdateController->handle('selection', Object)
call_user_func_array(Array, Array) (Line: 115)
Drupal\Core\Update\UpdateKernel->handleRaw(Object) (Line: 76)
Drupal\Core\Update\UpdateKernel->handle(Object) (Line: 28)
require('/Users/dawehner/Documents/www/drupal/update.php') (Line: 65)
Steps to reproduce:
- Install 8.8.1
- insert a schema into the key_value which no longer exists:
insert into key_value(collection, name, value) values ('system.schema', 'mymodule', 'i:8000;');I don't know how this ended up there, but it was definitely there on the site - Update the code to 8.8.5
- Hit update.php
- Sad panda
I did a git bisect which resulted into https://www.drupal.org/project/drupal/issues/2917600
@alexpott Pointed me to a bunch of issues which are out there: https://www.drupal.org/project/drupal/issues/3120910 for example. Applying that patch didn't help.
There's a related but separate bug: if there are orphaned entries in system.schema from modules that are still present in the filesystem but not installed, update.php currently tries to run those updates.
Proposed resolution
Add code to update.inc to better handle orphaned entries in system.schema k/v store:
- Skip (without errors) any entries that correspond to a module totally missing from the file system.
- Skip (without errors) any entries that correspond to present-but-not-installed modules.
- Add test coverage of these.
Remaining tasks
Decide if we need better (actionable) warning messages. See #23.Yes.Decide if we need a warning message / log entry about orphaned system.schema entries for not-installed modules. See #30.Why not? See #31.We need to edit the CR for this.@xjm, @catch and I agreed that the warning messages should link to the CR for more info. "See #45.<a href=":link">More information about this error.</a>tacked on the end."- <
a href="#comment-13620341">#36.2: I'll add more comments. But yes that hunk matters, and no it doesn't needSee #45.moduleExists()there. #36.3: Indeed, typo. s/non-existant/nonexistent/ (a vs. e, plus we don't need the hyphen).See #45.#40.See #45.- Further reviews / improvements.
- RTBC.
- Commit.
User interface changes
New warnings printed on update.php if there are orphaned entries in system.schema k/v store. Two possible cases:
- Module totally missing from the file system.
- Modules that are present but not currently installed.
Module %name has an entry in the system.schema key/value storage, but is missing from your site.
Module %name has an entry in the system.schema key/value storage, but is not installed.
Screenshot showing a site with both kinds of orphaned entries:

If a site only has 1 or the other, a single message is displayed:

API changes
None.
Data model changes
None.
Release notes snippet
TBD.

| Comment | File | Size | Author |
|---|---|---|---|
| #48 | 3136668-48.8_8_x.patch | 8.54 KB | dww |
| #48 | 3136668-48.8_9_x.patch | 8.56 KB | dww |
| #48 | 3136668-48.9_y_x.patch | 8.53 KB | dww |
Comments
Comment #2
dawehnerComment #3
dawehnerComment #4
dawehnerComment #5
dawehnerSomething like this resolves the problem for me. Turns out if you throw an exception catching that exception could be a good idea.
Working on a helpful testcase
Comment #6
dawehnerThis time with a test as well, sadly the patch above doesn't resolve that problem yet.
Comment #8
pavnish commentedComment #9
pavnish commented@dawehner in this patch i have remove extra space in comment.
Comment #10
pavnish commentedComment #11
jyotimishra-developer commentedRunning forcefully test on patch #9
https://dispatcher.drupalci.org/job/drupal_patches/45749/
Comment #12
jyotimishra-developer commentedpatch in #10 is failed to apply.
Comment #13
xjmOops, missed this one...
Comment #14
dwwHere's #5 + #6 in a single patch for 8.8.x.
Still fails locally. Here's why:
update_retrieve_dependencies()module_load_install()module_load_install()jumps through a few more hoops before it callsdrupal_get_filename().drupal_get_filename()does not throw exceptions on errors, but directly callstrigger_error(). :( There's no way to catch that.So the fix in #5 doesn't actually matter.Edit: I was wrong, see below.I'm not sure how to fix this cleanly without lots of BC breaking.
The yucky / bloaty approach is to not call
module_load_include()directly inupdate_retrieve_dependencies(), but to first use\Drupal::service("extension.list.module")and check that the module exists and is enabled before we try to callmodule_load_include(). Or something. :(Comment #15
dwwSweet, that wasn't nearly as bad as I feared. ;) This now passes locally. It's not even too terrible. Hope the inline comment is sufficient to explain why we need this.
Note: we still also need the fix from #5, so I'm leaving that in. If I take it out, the test starts failing again.
Comment #16
dwwForward port to 8.9.x and 9.y.x branches.
Comment #17
dwwOh, forgot to mention at #14. I slightly simplified the test:
This test class already has a
protected $updateUserwith that permission, so we should re-use that instead of creating another.Comment #19
dwwRe: #18: Random fail:
Re-queued...
Comment #20
shaktikHi @Dww,
this error is only getting on Drupal CI when automatic running or I check manually then working fine on drupal.org CI also in my local working fine.
I am getting the same error on
https://www.drupal.org/pift-ci-job/1683828
checked manually then working fine.
Comment #21
daffie commentedThe patch looks good.
The added test tests the problem as stated in the IS. I would like see a comment about the following line about why this line is here and what is does.
The fix to
update_get_update_list()is necessary, because without it the tests fails with:The fix to
update_retrieve_dependencies()is necessary, because without it the tests fails with:I like the added log the error stuff. In this way we will get a better understanding about where these bugs come from. :)
With the added comment, the patch will be for me RTBC.
Comment #22
catchI've added a brief note about this to #3130037: system.schema information gets out of sync with module list (which was already open to track modules having missing system.schema information), and retitled it so that it covers either direction of going out of sync.
Opened #3137197: Delete orphaned system.schema entries. to discuss automatically cleaning up the system.schema cruft (for Drupal 10).
Do we want to add a
\Drupal::messenger()warning in this issue, so that we have an additional chance to alert site owners that something is up? It could result in more reports of this which may help to track down the root cause.Another possible issue (or two):
1. If the module is in the code base, has the orphaned system.schema entry, but is not installed, will we then be locating and trying to run updates for it? i.e. have we accidentally re-introduced running updates on uninstalled modules when this happens?
2. If the module is not in the code base, but then is re-added, what happens if you try to install it again? Do we just ignore the system.schema entry and overwrite it, or does it cause problems?
I don't think #2 is as critical as this issue - since it would only prevent you re-installing that specific module as opposed to being able to run updates (i.e. we should split it out to a follow-up if it is), but #1 would be and could probably be handled here.
Comment #23
dww@shaktik Re: #20: I'm not understanding your comment. The tests are all working as expected, both on the drupal.org testbot and when running them locally. If you're seeing skipped tests locally, something is wrong with your testing environment. Helping you debug your setup is out of scope for me and my time today, sorry.
@daffie: Re: #21: Thanks for the review. Re:
\Drupal::keyValue('system.schema')->set('my_already_removed_module', 8000);, I was hoping that the name of the test (testNotExistingModuleInSchema()) and the existing summary ("Tests that orphan schemas don't prevent updates.") was sufficient. But I'm always up for more comments, so here you go. ;)@catch: Re: #22: Thanks for the review, follow-up and the questions.
Re:
dsm(): Sure, I guess that's fine. For now, duplicated exactly the message that gets logged. However, I'm worried that the message is sort of scary sounding but totally non-actionable for 99% of site admins. :(<hat class="average-site-builder"></hat>Not even drush gives you an easy way to clean up the k/v store. AFAIK, you have to do direct DB manipulations or PHP eval to try to clean this out.
Do we really want to present this to site admins like this? If so, I think we need a better message that either explains what to do, or at least links to a handbook page on d.o that does.
Re: #22.1: I can't fathom how adding code to update.inc that gives it more reasons to skip trying to run updates for something would re-introduce the bug you're talking about. 😉 Also, don't we already have existing test coverage of that original bug? If not, what happened?!? 😜 If so, why can't we trust it to make sure this hasn't re-broken it? I briefly skimmed through the rest of UpdateScriptTest.php and didn't see anything, but I'm not totally fluent in all the update.php tests and what they cover. Seems out of scope here to add such coverage if it doesn't already exist, especially since it seems impossible that this change would re-trigger that bug. This patch only makes it more likely that we don't try to run updates we shouldn't run.
Re: #22.2: That seems to work just fine:
So probably NW for a better message to show admins and stuff in the logs. Perhaps we need a handbook page first so we can link to it. TBD. /shrug
Comment #24
dwwp.s. at #3110198-53: [META] Beta targets following Drupal 9.0.0-beta1 and 8.9.0-beta1 @catch wrote:
Not worth bot cycles for this (yet), but FYI, the 8_8_x patch applies cleanly to 8.7.x branch and the new test passes there, too.
Comment #25
daffie commentedAdded a
\Drupal::messenger()warning to the patch as requested by @catch.Added a comment to the test as requested by myself.
The warning message text could/should be improved, only nobody has any idea.
As this issue is blocking the release of 9.0-rc1, I am not going to block it on a better warning message text.
All code changes look good to me.
For me it is RTBC.
Comment #26
catchI don't mean that this issue will re-introduce a bug, I'm asking whether we have a separate bug related to orphaned
system.schemaentries that is not covered here, potentially introduced by #2917600: update_fix_compatibility() puts sites into unrecoverable state.The current patch and test coverage covers:
A module, that was previously installed, that has orphaned data in
system.schema, that is no longer in the file system.It does not cover:
A module, that was previously installed, that has orphaned data in
system.schema, that is still in the file system.In that case, there will probably not be an exception thrown from ::checkIncompatibility(), and
system.schemais returning 8000 or whatever instead ofSCHEMA_UNINSTALLED- so, what happens? Do we hit an error later? Do the updates get added to the list? Does it get filtered out again somewhere when we switch back to extension.list instead of system.schema in a foreach so that things are eventually fine? Even if there's not a functional bug in the end, we should add test coverage for that.Comment #27
dww@catch: Thanks for clarifying! Now I understand you. Indeed, that's broken. :( Sounds like we need to fix that here?
Comment #29
dwwThis fixes the new test. Not sure if this is cool, or will break something else. Let's see if the bot spots any other troubles.
Comment #30
dwwOkay, so that's encouraging. The bot is happy with all the other update tests with the fix in #29. Yay.
Here's the interdiff between patches 23 and 28, which might be more clear than the intervening interdiffs since there's nothing about drupalci.yml in this.
Updating summary a bit now that this is getting closer to done.
One thought on the fix from #29: do we want to detect that case explicitly and add another dsm/log message about it? Honestly, the existing message is more accurate for the present-but-not-installed case:
Perhaps we should change the message in the not-present case to something like:
If we're changing the messages, perhaps we can make them more clear / actionable, too (see #23).
Thoughts?
Thanks,
-Derek
Comment #31
dwwThis handles the possible error conditions separately so we can have more specific warning messages:
Comment #32
dwwMore specific tests. Not sure this is an improvement over #31, but instead of checking the whole page, make sure the status text is in a status message, and that the warning text is in a warning message. /shrug Stark doesn't use classes, so instead of searching for
div.messages-status, we need toxpath()for@aria-label="Status message"...Adds coverage that there aren't unexpected warnings.
Also adds coverage for the situation where both warnings are displayed.
Finally, I'm removing a stay visit to the status report that's from the original test in #6:
Seems we don't need that as part of this test...
Comment #33
dwwSorry, patches in #32 were a bit wonky. Didn't correctly apply the changes to all the branches. Try these, instead.
Comment #34
dwwIn case it's helpful, interdiff between #31 and #33...
Comment #35
daffie commentedThis is what @catch wants to add to the patch. The added check:
if (!$module_handler->moduleExists($module)) {does exactly that. There is also automatic testing added in the patch for that.All points of @catch are addressed.
All code changes look good.
Back to RTBC.
Comment #36
catchThis is looking a lot better, comments are not major but the second one means back to Needs Review.
+1 on the changed messages. Also makes it much clearer exactly what the different error conditions are by moving (compared to earlier patches) the ::moduleExists() check under a dedicated comment.
This doesn't have the ::moduleExists() check, does that matter? Also the comment doesn't mention orphaned system.schema entries. Is the hunk even needed with the rest of the patch?
Nit: shouldn't this be existent? Or is that British vs. American?
I think there's an extra step involved to reach this condition 1. You had the module installed but removed it from the filesystem without uninstalling 2. You 'manually' uninstalled in extension.list without removing the system.schema entry. If the module is in extension.list but not the filesystem, that's a different problem for which we already have error messages.
Also maybe this is actually how people are getting into this position? If so we might not actually have a core bug causing this as such.
Comment #37
alexpottI don;t think we need a new dependency here. The extension list know which modules are installed. See \Drupal\Core\Extension\ExtensionList::getInstalledExtensionNames()
Comment #38
pavnish commentedComment #39
pavnish commentedHi @alexpott this the protected method i think we can not use directly in .inc file.This function can we use by using the class.
One more think this function has implemented on "extension.list.module" service in protected manner which internally use "$this->moduleHandler->getModuleList()" .
So i think it was not an issue
Please correct me if am wrong.
Comment #40
alexpott@pavnish good point. We can get a list using \Drupal\Core\Extension\ExtensionList::getAllInstalledInfo() and then check if the module is not in this list.
Comment #41
alexpottOne concern is what is the correct action to take at this point. We can:
All pretty awkward but what we're currently doing is probably best.
Comment #42
catchWe have #3137197: Delete orphaned system.schema entries. for deleting entries, I'm suggesting doing that in Drupal 10 in an update.
The big question with this is whether things getting out of sync is due to force-uninstalls by admins - in which case it's good to handle and warn about it, but ultimately self-inflicted, or due to core and contrib bugs - like a fatal error during uninstall. And also whether we can ever prevent either of those from happening permanently.
Comment #43
shaktikComment #44
dwwDiscussed this in the #d9readiness meeting today. I'll work on the following:
<a href=":link">More information about this error.</a>tacked on the end."moduleExists()there. If you remove that hunk, the test fails like so:As it says, we can't call
module_load_install()on something not in the filesystem or we get an uncatchabletrigger_error(), not an exception. This is actually inupdate_retrieve_dependencies(). We don't need to filter out not-installed here, because that happens inupdate_get_update_list(). We could also filter those out here, and the tests still pass, but that seems like maybe scope creep? I defer to core committers on their preference for this.Comment #45
dwwVery preliminary CR here: https://www.drupal.org/node/3137656 -- If anyone wants to edit that to be real, please do. ;)
This fixes everything else I mentioned in #44. This is only the 8.8.x branch patch. I'll forward port after breakfast, assuming folks are happy with all this.
Comment #46
dwwForward ports.
Comment #47
dwwInitial real version of the CR: https://www.drupal.org/node/3137656/revisions/view/11880555/11880653
Also, refreshing the screenshots, now that we have a link in the warning messages.
Comment #48
dwwI reworded the warnings to be a bit more useful for mere mortals:
Now:
p.s. "Maybe "key/value service..." would be better than "storage"?
Comment #49
daffie commentedThe CR is to me good enough. It has a good describtion about the newly added warning message. Including what a siteowner can do to cleanup the error.
All shown warnings are also logged and all have a link to the CR.
There are 2 different warnings that are shown, depending on whether the source module is on the file system or not. For both and for the combination is automatic testing added.
All code changes look good to me and all are very commented.
We have a followup for cleaning up the orphaned system.schema entries. See: #3137197: Delete orphaned system.schema entries..
For it is all good enough. We need to ship Drupal 9.0 and not spending a lot of time trying to get this issue perfect. Even so, I must say that the effort of @dww is very much appreciated!
For me it is RTBC.
Comment #52
catchThanks for the CR and the additional comments/message improvements, all looks good to me now.
Committed/pushed to 9.1.x, cherry-picked to 9.0.x, and then the 8.9.x and 8.8.x patches, thanks!
Comment #54
dww@catch Thanks! Looks like you didn't push the 8.8.x commit...
Comment #56
catchHmm, now pushed!
Comment #57
dwwWonderful, thanks.