Problem/Motivation

If config makes its way to that active/target store with a missing UUID Drupal's config system has trouble handling the value. This can lead to database stores in an inconsistent and difficult to fix state requiring direct modification of the database store in the database.

Steps to reproduce

Users have ended up in this state but difficult to isolate the cause. Only reliable way seems to be manual database interactions.

Proposed resolution

Make StorageComparer more resilient to the edge case and self heal the target by triggering a recreation of the config item.

Remaining tasks

User interface changes

n/a

Introduced terminology

n/a

API changes

n/a

Data model changes

n/a

Release notes snippet

n/a. Normal bug fix.

Original report by john cook

Config import creates "Undefined index: uuid" notice

In our use case we have two seach_api index sett-ups; one for local development and one for staging / produdction.

On deployment we use drush cset search_api.server.index status false to select the appropiate configuration.

This works fine for trash and rebuild on the local development machines, but when the configuration in imported on the persitent environments the following error is produced:

Notice: Undefined index: uuid in Drupal\Core\Config\StorageComparer->addChangelistUpdate() (line 262 of docroot/core/lib/Drupal/Core/Config/StorageComparer.php)
#0 docroot/core/includes/bootstrap.inc(548): _drupal_error_handler_real(8, 'Undefined index...', '/mnt/www/html/h...', 262, Array)
#1 docroot/core/lib/Drupal/Core/Config/StorageComparer.php(262): _drupal_error_handler(8, 'Undefined index...', '/mnt/www/html/h...', 262, Array)
#2 docroot/core/lib/Drupal/Core/Config/StorageComparer.php(206): Drupal\Core\Config\StorageComparer->addChangelistUpdate('')
#3 docroot/core/modules/config/src/Form/ConfigSync.php(181): Drupal\Core\Config\StorageComparer->createChangelist()
#4 [internal function]: Drupal\config\Form\ConfigSync->buildForm(Array, Object(Drupal\Core\Form\FormState))
#5 docroot/core/lib/Drupal/Core/Form/FormBuilder.php(514): call_user_func_array(Array, Array)
#6 docroot/core/lib/Drupal/Core/Form/FormBuilder.php(271): Drupal\Core\Form\FormBuilder->retrieveForm('config_admin_im...', Object(Drupal\Core\Form\FormState))
#7 docroot/core/lib/Drupal/Core/Controller/FormController.php(74): Drupal\Core\Form\FormBuilder->buildForm(Object(Drupal\config\Form\ConfigSync), Object(Drupal\Core\Form\FormState))
#8 [internal function]: Drupal\Core\Controller\FormController->getContentResult(Object(Symfony\Component\HttpFoundation\Request), Object(Drupal\Core\Routing\RouteMatch))
#9 docroot/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php(123): call_user_func_array(Array, Array)
#10 docroot/core/lib/Drupal/Core/Render/Renderer.php(574): Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}()
#11 docroot/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php(124): Drupal\Core\Render\Renderer->executeInRenderContext(Object(Drupal\Core\Render\RenderContext), Object(Closure))
#12 docroot/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php(97): Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext(Array, Array)
#13 [internal function]: Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}()
#14 /mnt/www/html/hiscoxukstg/vendor/symfony/http-kernel/HttpKernel.php(144): call_user_func_array(Object(Closure), Array)
#15 /mnt/www/html/hiscoxukstg/vendor/symfony/http-kernel/HttpKernel.php(64): Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object(Symfony\Component\HttpFoundation\Request), 1) #16 docroot/core/lib/Drupal/Core/StackMiddleware/Session.php(57): Symfony\Component\HttpKernel\HttpKernel->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#17 docroot/core/lib/Drupal/Core/StackMiddleware/KernelPreHandle.php(47): Drupal\Core\StackMiddleware\Session->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#18 docroot/core/modules/page_cache/src/StackMiddleware/PageCache.php(99): Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#19 docroot/core/modules/page_cache/src/StackMiddleware/PageCache.php(78): Drupal\page_cache\StackMiddleware\PageCache->pass(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#20 docroot/core/lib/Drupal/Core/StackMiddleware/ReverseProxyMiddleware.php(47): Drupal\page_cache\StackMiddleware\PageCache->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#21 docroot/core/lib/Drupal/Core/StackMiddleware/NegotiationMiddleware.php(50): Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#22 /mnt/www/html/hiscoxukstg/vendor/stack/builder/src/Stack/StackedHttpKernel.php(23): Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#23 docroot/core/lib/Drupal/Core/DrupalKernel.php(652): Stack\StackedHttpKernel->handle(Object(Symfony\Component\HttpFoundation\Request), 1, true)
#24 docroot/index.php(19): Drupal\Core\DrupalKernel->handle(Object(Symfony\Component\HttpFoundation\Request))
#25 {main}.

Issue fork drupal-2863785

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

John Cook created an issue. See original summary.

john cook’s picture

Status: Active » Needs review
StatusFileSize
new948 bytes

I've create a patch that adds a check to ensure that $target_data['uuid'] has been set. This makes sure that the configuration is recreated before trying to compare uuids.

john cook’s picture

StatusFileSize
new2.56 KB

This adds checks for ConfigEntityStorageInterface::getIDFromConfigName() returning NULL.

Version: 8.4.x-dev » 8.5.x-dev

Drupal 8.4.0-alpha1 will be released the week of July 31, 2017, which means new developments and disruptive changes should now be targeted against the 8.5.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.5.x-dev » 8.6.x-dev

Drupal 8.5.0-alpha1 will be released the week of January 17, 2018, which means new developments and disruptive changes should now be targeted against the 8.6.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

Version: 8.6.x-dev » 8.7.x-dev

Drupal 8.6.0-alpha1 will be released the week of July 16, 2018, which means new developments and disruptive changes should now be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

firfin’s picture

Status: Needs review » Reviewed & tested by the community

Applied the patch on a Drupal 8.5.5 running on php 7.0 applied with just some offsets, no problems. Afterwards no more UUID errors.
Code looks clean also.

That said I have absolutely no clue as to this is the right solution to solve the error.

alexpott’s picture

Status: Reviewed & tested by the community » Needs work
Issue tags: +Needs tests

At the very least this needs tests.

Also the patch in #3 is failing tests.

I think a more complete description of the problem and perhaps a test that causes the problem would be a good place to start since I have no idea why the config importer is dealing with configuration entities without a UUID.

Version: 8.7.x-dev » 8.8.x-dev

Drupal 8.7.0-alpha1 will be released the week of March 11, 2019, which means new developments and disruptive changes should now be targeted against the 8.8.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

claudiu.cristea’s picture

@alexpott

I think a more complete description of the problem and perhaps a test that causes the problem would be a good place to start since I have no idea why the config importer is dealing with configuration entities without a UUID.

We hit the same error on a project built in the early stages of D8. Some config entries from the database were imported without an UUID, directly from the module's default config. Don't ask how they landed there without an UUID. Perhaps because the project used initially a very old version of config_sync module. I have no clear understanding. The fact is that the site is in production for > 2 years and the configs are there from a long time.

I think the solution from #2 makes sense, as it will replace the config from the database as if their UUID is different and would heal the database store.

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.0-alpha1 will be released the week of October 14th, 2019, which means new developments and disruptive changes should now be targeted against the 8.9.x-dev branch. (Any changes to 8.9.x will also be committed to 9.0.x in preparation for Drupal 9’s release, but some changes like significant feature additions will be deferred to 9.1.x.). For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 8.9.x-dev » 9.1.x-dev

Drupal 8.9.0-beta1 was released on March 20, 2020. 8.9.x is the final, long-term support (LTS) minor release of Drupal 8, which means new developments and disruptive changes should now be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

achap’s picture

To add some more context to this issue.

I experienced it on a project that was heavily using config_split that I inherited that was creating new splits from the config in an example split directory via a script. These example configs didn't have a uuid so we got the error message. I was able to run the import, which completed successfully and after page refresh the error message went away. Obviously, that's not a "fix" but there you go.

I have no idea why the original config didn't have a uuid.

Version: 9.1.x-dev » 9.2.x-dev

Drupal 9.1.0-alpha1 will be released the week of October 19, 2020, which means new developments and disruptive changes should now be targeted for the 9.2.x-dev branch. For more information see the Drupal 9 minor version schedule and the Allowed changes during the Drupal 9 release cycle.

Version: 9.2.x-dev » 9.3.x-dev

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

marlon.buella made their first commit to this issue’s fork.

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

jungle’s picture

FYI, admin_toolbar module's admin_toolbar.settings.yml exported has no uuid key.

Drupal core: 9.3.22
admin_toolbar:3.2.1

jungle’s picture

captcha.settings.yml exported from captcha as well

Version: 9.5.x-dev » 10.1.x-dev

Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

prashant.c’s picture

Priority: Normal » Major

We are also experiencing this issue on our site which was built on Drupal 8.6 and now upgraded to Drupal 10.0.8. Some of the configs like admin toolbar, advagg, etc.do not have UUIDs, I also doubt it is happening due to those.

Changing to Major as it is a blocker during config export/import.

Version: 10.1.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

neclimdul’s picture

Priority: Major » Normal
Status: Needs work » Needs review
StatusFileSize
new3.08 KB

Webform also triggers this with its default contact form when installing from config.

Don't think a notice qualifies for major. If someone could help me recreate the fatal from the load failures addressed in #4 maybe we can bump it back but I suspect that might be a different maybe related issue. Until then it will also be difficult to create a realistic test for it.

Here's an updated patch for Drupal 10 with just the uuid handling (since I don't know how to recreate and test the load failure) and a test.

neclimdul’s picture

  1. +++ b/core/tests/Drupal/Tests/Core/Config/StorageComparerTest.php
    @@ -284,6 +284,50 @@ public function testDifferentCollections() {
    +    $recreate_expected = [
    +      'field.storage.node.body',
    +      // TODO Should this be recreated?
    +      'views.view.test_view',
    +    ];
    

    This asserts the existing behavior with the undefined property evaluating to null. Is recreating actually correct though? That seems kinda odd.

  2. +++ b/core/tests/Drupal/Tests/Core/Config/StorageComparerTest.php
    @@ -284,6 +284,50 @@ public function testDifferentCollections() {
    +    // TODO does asserting the order matter here?
    +    $this->assertEqualsCanonicalizing($recreate_expected, $this->storageComparer->getChangelist('create'));
    +    $this->assertEqualsCanonicalizing($recreate_expected, $this->storageComparer->getChangelist('delete'));
    

    I don't know if the order matters here. Or if we need to assert it since its probably better tested else where. I would appreciate someone more familiar with the methods chiming in here.

needs-review-queue-bot’s picture

Status: Needs review » Needs work

The Needs Review Queue Bot tested this issue.

While you are making the above changes, we recommend that you convert this patch to a merge request. Merge requests are preferred over patches. Be sure to hide the old patch files as well. (Converting an issue to a merge request without other contributions to the issue will not receive credit.)

teodorakis changed the visibility of the branch 2863785-config-import-creates to hidden.

teodorakis changed the visibility of the branch 2863785-config-import-creates to active.

alexpott’s picture

@neclimdul if webform is creating entities without a UUID then that's a bug in webform - no?

therobyouknow’s picture

I got this doing a drush cex

A drush cr
- clear cache

appeared to resolve it

My Drupal version 10.0.9 (need to upgrade to latest)

therobyouknow’s picture

this has come back

when developing drupal code to share with others, I would want to remove the uuid
https://drupal.stackexchange.com/questions/295320/best-practice-remove-u...

however, I believe in doing so, it causes the "Undefined index: uuid". This post appears to explain: https://drupal.stackexchange.com/questions/204859/site-uuid-in-source-st...

Version: 11.x-dev » main

Drupal core is now using the main branch as the primary development branch. New developments and disruptive changes should now be targeted to the main branch.

Read more in the announcement.

graber’s picture

StatusFileSize
new3.08 KB

Re-rolled for a certain project but yes, it's the config that should be fixed.

neclimdul’s picture

Title: Config import creates "Undefined index: uuid" notice » Repair config with missing uuid in active store by recreating
Issue summary: View changes
Status: Needs work » Needs review

yeah, I think the problem was more that the config to fix was the database store so fixing would require manual queries to serialized data structures. That or recreating the config by deleting and re-importing manually similar to proposed solution. The intention of the patch as claudiu put it was to let the config system detect and heal a bad database store.

Looking at the patch after many years, that's a bit difficult to see so I split the code out with a comment so hopefully that will make review and acceptance easier.

At this point I think config is at lot more stable and users that would have run into this probably already have and worked through but the patch should guard against future users getting into a bind.

Also updated title and IS to reflect what's being proposed.

andypost’s picture

smustgrave’s picture

Status: Needs review » Reviewed & tested by the community
Issue tags: -Needs tests +Bug Smash Initiative, +Needs Review Queue Initiative

Removing the test tag as it doesn't cause an error but does generate a warning

1) /var/www/html/core/lib/Drupal/Core/Config/StorageComparer.php:303
Undefined array key "uuid"

Can't run in the pipeline because of my role so did it locally.

Very neat approach setting it to NULL to fix itself. Comment is very nice too.

0 objections LGTM.

alexpott’s picture

Status: Reviewed & tested by the community » Needs work

This does seem like a reasonable hardening but I don't think we should actually be setting the uuid in the target data here. This ends up changing the target data when it should not. Leaving a review and suggestion on the MR.

neclimdul’s picture

Status: Needs work » Needs review

Review addressed

smustgrave’s picture

Status: Needs review » Reviewed & tested by the community

Feedback from @alexpott appears to be addressed

john.oltman’s picture

Title: Repair config with missing uuid in active store by recreating » Avoid PHP notice when comparing config without uuid
john.oltman’s picture

Updated the title since the MR does not actually repair storage anymore (at least in any different way than before).

If I am right, the issue description needs an update. If I am wrong, my apologies, please reset the title back. However, from what I can tell, the behavior of storage has not changed in the MR, other than an edge case no longer throwing a notice. I ran into this notice with config from the editoria11y contrib module, and the MR fixed it.

alexpott’s picture

@john.oltman - well I guess you could consider it repairing when you run the import and it recreates the config with a uuid. But your new title is more accurate.

alexpott’s picture

Version: main » 11.4.x-dev
Status: Reviewed & tested by the community » Fixed

Committed and pushed c8bda45c62b to main and 23a4af7850e to 11.x. Thanks!

Committed 89b938b and pushed to 11.4.x. Thanks!

Now that this issue is closed, review the contribution record.

As a contributor, attribute any organization that helped you, or if you volunteered your own time.

Maintainers, credit people who helped resolve this issue.

  • alexpott committed 89b938b4 on 11.4.x
    fix: #2863785 Avoid PHP notice when comparing config without uuid
    
    By:...

  • alexpott committed 23a4af78 on 11.x
    fix: #2863785 Avoid PHP notice when comparing config without uuid
    
    By:...

  • alexpott committed c8bda45c on main
    fix: #2863785 Avoid PHP notice when comparing config without uuid
    
    By:...
vidit.anjaria’s picture

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.