Trying to save any theme settings form results in WSoD

Created on 21 April 2023, about 1 year ago
Updated 3 May 2023, about 1 year ago

Problem/Motivation

With Config Enforce Devel installed, try to save any theme form, be it Claro, Olivero, or even Stark, and you get a big old white screen of death with this:

The website encountered an unexpected error. Please try again later.

Drupal\Core\Config\ConfigValueException: stark.settings key contains a dot which is not supported. in Drupal\Core\Config\ConfigBase->validateKeys() (line 211 of core/lib/Drupal/Core/Config/ConfigBase.php).

Drupal\Core\Config\ConfigBase->set('config_enforce', Array) (Line: 184)
Drupal\Core\Config\Config->set('config_enforce', Array) (Line: 503)
theme_settings_convert_to_config(Array, Object) (Line: 511)
Drupal\system\Form\ThemeSettingsForm->submitForm(Array, Object)
call_user_func_array(Array, Array) (Line: 114)
Drupal\Core\Form\FormSubmitter->executeSubmitHandlers(Array, Object) (Line: 52)
Drupal\Core\Form\FormSubmitter->doSubmitForm(Array, Object) (Line: 595)
Drupal\Core\Form\FormBuilder->processForm('system_theme_settings', Array, Object) (Line: 323)
Drupal\Core\Form\FormBuilder->buildForm(Object, Object) (Line: 73)
Drupal\Core\Controller\FormController->getContentResult(Object, Object)
call_user_func_array(Array, Array) (Line: 123)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() (Line: 580)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 124)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext(Array, Array) (Line: 97)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() (Line: 169)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 81)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 106)
Drupal\page_cache\StackMiddleware\PageCache->pass(Object, 1, 1) (Line: 85)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 718)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)

Steps to reproduce

See above.

Proposed resolution

Not sure, but we need to figure out why we're passing a config key with a dot in it to Drupal, because that's causing the error. We'll likely need to escape it by replacing it with another character, such as a colon (:).

Remaining tasks

¯\_(ツ)_/¯

User interface changes

It no break no more.

API changes

None?

Data model changes

None?

🐛 Bug report
Status

Fixed

Version

1.0

Component

Code

Created by

🇨🇦Canada Ambient.Impact Toronto

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

  • Issue created by @Ambient.Impact
  • 🇨🇦Canada Ambient.Impact Toronto

    After some digging through our code and Drupal core's, it looks like the problem is partially caused by \Drupal\system\Form\ThemeSettingsForm::submitForm() passing the entire theme settings values to theme_settings_convert_to_config() which then attempts to set all top level items in the array it was passed as config keys, which causes Drupal's configuration system to throw an exception because a config key with a dot in it is not valid, due to that character having a special meaning in the configuration system.

    We've got a couple of options:

    1. We could try and fix just this one form; to do that, we could probably insert our own submit handler so that it runs before ThemeSettingsForm::submitForm() and fix the issue there by escaping the dots in the config name, i.e. replacing them with a colon (:), or:
    2. We could do the above but for all forms, to prevent such an error in other places we may not have thought of. This might require a bit more care to ensure we also unescape the configuration name in all cases when/if we retrieve it from the form.

    Regardless of which we choose, we should create a basic test to ensure the theme settings form can be submitted successfully and without an error.

  • @ambientimpact opened merge request.
  • Open in Jenkins → Open on Drupal.org →
    Core: 9.5.x + Environment: PHP 7.4 & MySQL 5.7
    last update about 1 year ago
    2 pass, 2 fail
  • 🇨🇦Canada Ambient.Impact Toronto

    I added a test to demonstrate the problem. I've run it locally to verify that it does indeed detect the fatal error. The test is currently queuing and is expected/intended to fail.

  • 🇨🇦Canada ergonlogic Montréal, Québec 🇨🇦

    This occurs whether we're trying to enforce the theme config or not. It seems odd that CED would be triggered at all.

  • 🇨🇦Canada Ambient.Impact Toronto

    @ergonlogic Yeah, it looks like the theme form is passing our form elements over to the configuration system, so that would be why. Those form elements are always added even when not enforcing.

  • 🇨🇦Canada ergonlogic Montréal, Québec 🇨🇦

    Part of the goal for Improve usability of Config Enforce Devel's UI Postponed is to move the Config Enforce form elements into their own form. Accomplishing that ought to resolve this issue, and any similar ones.

  • 🇨🇦Canada Ambient.Impact Toronto

    It would solve a number of problems for sure and I'd like to get that done, but it'll probably take a while to do so maybe we can implement a workaround for now with a clear @deprecated and/or @todo tag that the workaround will be removed before 2.0.0, which is when we'll totally rework the UI. How does that sound?

  • 🇨🇦Canada ergonlogic Montréal, Québec 🇨🇦

    Sure, that makes sense. But let's limit the scope to solving the problem with theme settings, rather than trying to anticipate similar issues.

    We could, for example, just add `system_theme_settings` to the form deny-list, which resolves this issue. It can then be properly resolved as part of Support adding enforced configs to themes Active , for v2.0.0

  • 🇨🇦Canada Ambient.Impact Toronto

    Yup, we can limit the fix to this form. I think I'd prefer to not add the form to the deny list just because it feels a bit weird from a UX point of view, in that this might become an annoyance if we can't quickly go to the form to enforce something that might turn out to be common in the future.

  • Open in Jenkins → Open on Drupal.org →
    Core: 9.5.x + Environment: PHP 7.4 & MySQL 5.7
    last update about 1 year ago
    3 pass
  • Assigned to Ambient.Impact
  • Status changed to Needs work about 1 year ago
  • 🇨🇦Canada Ambient.Impact Toronto

    Alright, so I might have done a deep dive while sleep deprived and a bit delirious but finally figured out how to work around this nasty issue. I pushed a commit that isn't even remotely ready (it's a mess and has commented out debug stuff), but wanted to get this up here so you can see what I'm doing. I'll revisit this tomorrow when I'm less sleep deprived and hopefully refine it and fix it up.

  • Open in Jenkins → Open on Drupal.org →
    Core: 9.5.x + Environment: PHP 7.4 & MySQL 5.7
    last update about 1 year ago
    3 pass
  • 🇨🇦Canada Ambient.Impact Toronto

    Alright, so it's still a mess but I fixed the remaining issue which was that the system theme settings form submit handler was still saving our enforced config form values because it's dumb so I made sure our submit handler runs before core's and removes our values from the form state after it's done with them.

    It's still a mangled mess that needs to be refactored as a trait or something to contain this so it's easy to remove once we don't need it anymore, either because core reworks the form or we pull our enforce form out of the parent form and into a standalone form when Improve usability of Config Enforce Devel's UI Postponed is completed, whichever occurs first.

  • 🇨🇦Canada Ambient.Impact Toronto

    Uh, whoops, I broke every non-theme settings form embedded form. Working on it.

  • Open in Jenkins → Open on Drupal.org →
    Core: 9.5.x + Environment: PHP 7.4 & MySQL 5.7
    last update about 1 year ago
    3 pass
  • Open in Jenkins → Open on Drupal.org →
    Core: 9.5.x + Environment: PHP 7.4 & MySQL 5.7
    last update about 1 year ago
    3 pass
  • 🇨🇦Canada Ambient.Impact Toronto

    I probably spent more time on this than I should have - and I still need to properly document/comment the trait code - but on the plus side, I got a bit more familiar with the form and form handler architecture which will come in handy later.

  • Open in Jenkins → Open on Drupal.org →
    Core: 9.5.x + Environment: PHP 7.4 & MySQL 5.7
    last update about 1 year ago
    3 pass
  • Issue was unassigned.
  • Status changed to Needs review about 1 year ago
  • 🇨🇦Canada spiderman Halifax, NS

    I have to concur, this looks like it may have ended up being more trouble than just doing the form separation work, but I am fully aware how much easier it can be to see that in hindsight. That said, now that it's done and passing tests, I see no reason *not* to merge it, really. I appreciate that it's nicely segmented off, and if we do end up implementing the "proper" fix (separating forms) on the 2.x branch, at least this gives a workaround for folks who (unfathomably) are still using our 1.x branch and trying to enforce theme settings without throwing 500s :)

  • Open in Jenkins → Open on Drupal.org →
    Core: 9.5.x + Environment: PHP 7.4 & MySQL 5.7
    last update about 1 year ago
    3 pass
  • Status changed to Fixed about 1 year ago
  • 🇨🇦Canada Ambient.Impact Toronto

    Agreed on all points!

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

Production build 0.69.0 2024