SchemaCheckTrait::checkConfigSchema() is used to check if the passed in configuration matches its schema.
It is used by:
\Drupal\Core\Config\Development\ConfigSchemaChecker(which runs for tests if$this->strictConfigSchema === TRUE, which is the default for allKernelandFunctionaltests), which automatically validates all config that is saved during tests\Drupal\Tests\SchemaCheckTestTrait::assertConfigSchema()(which individual tests can choose to use to validate config even without having to save it, this is primarily used by migration tests)
This checks for example that something which should be a string in configuration is indeed a string and not an integer or a boolean.
Problem
But of course, often one does not just want a string. But a particular kind of string. For example: a UUID (so type: uuid instead of type: string). The UUID type
type: uuid was the first config schema type to gain explicit validation support (#2870878: Add config validation for UUIDs). The validation performed by SchemaCheckTrait was superficial for historical reasons: it only checks if the storage type is correct (e.g. string vs integer vs boolean). That means that even 'foobar' would be treated as a valid UUID, because the storage type for a UUID is … a string (in other words: any string).
That is what #3361534: KernelTestBase::$strictConfigSchema = TRUE and BrowserTestBase::$strictConfigSchema = TRUE do not actually strictly validate changes: rather than only validating the storage type, the validation constraints are now also executed.
Consequences
This may require some tests to be updated because historically Drupal would have not warned in many cases where invalid config was being used. Drupal core itself made a number of mistakes against this too. Fortunately, the error messages in the test failures tell you exactly what is wrong. More importantly, this helps tests be more representative of the real world, and helps discover subtle edge case bugs.
Ignored failures
Some invalid configuration may be ignored, thanks to \Drupal\Core\Config\Schema\SchemaCheckTrait::$ignoredPropertyPaths (which #3364109: Configuration schema & required values: add test coverage for `nullable: true` validation support added): that lists per top-level config schema data type (i.e. the root config schema type u sed by config objects or config entity types) and per property path in that top-level config schema data type which violation constraint messages should be ignored. A sample:
'block.block.*' => [
'weight' => [
'This value should not be null.',
],
'provider' => [
'This value should not be null.',
],
],
(this ignores the This value should not be null. violation error message triggered by the NotNull constraint for the weight and provider property paths on Block config entities)
'system.date' => [
// @todo Fix config or tweak schema of `type: system.date`.
// @see system.schema.yml
'timezone.default' => [
'This value should not be null.',
],
],
(this ignores the This value should not be null. violation error message triggered by the NotNull constraiont for the timezone.default property path on the system.date simple config)
Specific config items can be ignored in tests by defining them in the $configSchemaCheckerExclusions property.
Contrib: no test failures, only deprecation notices
The above made it sound like invalid configuration would cause tests to fail. This is true only in Drupal core. For contrib/custom extensions (themes, modules, profiles), invalid configuration causes only deprecation notices, not test failures. In Drupal 11, these will become actual test failures.
Exception to the rule: contrib modules that alter the set of allowed values. For example, imagine that a module adds a new possible value for the CKEditor 5 "Language" plugin: in addition to core's support for un, all and site_configured it adds support for site_configured_unless_pirate_day (which would use core's PirateDayCacheContext, obviously.) Well, in that case it'd have to do something like:
function MYMODULE_config_schema_info_alter(&$definitions) {
$definitions['ckeditor5.plugin.ckeditor5_language']['mapping']['language_list']['constraints']['Choice'][] = 'site_configured_unless_pirate_day';
}
Example
Example test failure:
- Let's say
media.settings.ymllooks like this:
icon_base_uri: 'public://media-icons/generic' iframe_domain: '' oembed_providers_url: "Ceci n'est pas une URL." standalone_url: false -
Then this test failure is expected:
1) Drupal\Tests\media\Kernel\OEmbedIframeControllerTest::testBadHashParameter with data set "no hash" ('') Exception: Exception when installing config for module media, message was: Schema errors for media.settings with the following errors: 0 [iframe_domain] This value should be of the correct primitive type., 1 [oembed_providers_url] This value should be of the correct primitive type. -
That failure messsage says that for the
media.settingsconfiguration there were two errors:[iframe_domain] This value should be of the correct primitive type.→ the value for theiframe_domainkey is not of the correct primitive type.[oembed_providers_url] This value should be of the correct primitive type.→ the value for theoembed_providers_urlkey is not of the correct primitive type.
-
Looking at the config schema for
media.settingsinmedia.schema.yml, we see that both havetype: uri. - Clearly
"Ceci n'est pas une URL."is not a URL. Changing it back to its default value of'https://oembed.com/providers.json'fixes this. - But the empty string (
'') that is set foriframe_domaindoes look fine? 🤔 Ah, but the empty string not a valid URI!💡 So the problem here is that the config schema has a bug: it does not allow expressing that this key-value pair is optional. We can fix that by:- adding
nullable: trueto the config schema - changing the value for the
iframe_domainkey to~(which meansNULLin YAML)
- adding
- Done!
Takeaway
In this example we saw two different cases:
- The value for some key-value pair in some configuration was wrong. Solution: fix the value.
- The value for some key-value pair in some configuration looked right, but was not accepted. Solution: broaden the config schema.
Analyzing lots of config
When you need to analyze a lot of configuration for its validity, use the Configuration Inspector's Drush command, which since version 2.1.1 has an optional --strict-validation flag:
drush config:inspect --strict-validation
to check one piece of configuration at the time:
drush config:inspect --filter-keys=media.settings --strict-validation