`PageRegion::createFromBlockLayout()` fatals with an `assert()` failure for any block carrying a `context_mapping` setting (e.g. Views blocks with a contextual filter)
## Problem
Saving the core "Appearance > Settings" (`system_theme_settings`) form for a theme
that already has Drupal Canvas enabled (i.e. any `canvas.page_region.<theme>.*`
config entity already exists) throws an uncaught `AssertionError` and returns a
fatal error page, for example when simply uploading a new theme logo:
```
AssertionError: assert([] === iterator_to_array($page_region->getTypedData()->validate())) in assert() (line 348 of modules/contrib/canvas/src/Entity/PageRegion.php)
Drupal\canvas\Entity\PageRegion::createFromBlockLayout() (Line: 75)
Drupal\canvas\Hook\PageRegionHooks::formSystemThemeSettingsSubmit() (Line: 108)
...
```
Because the "Use Drupal Canvas for page templates" checkbox defaults to checked
once any `PageRegion` exists for the theme, this fires on **every** save of the
theme settings form, not just when a site builder is intentionally reconfiguring
Canvas regions — including routine actions like changing the logo or favicon.
## Root cause
`PageRegionHooks::formSystemThemeSettingsSubmit()` calls
`PageRegion::createFromBlockLayout($theme)` unconditionally whenever the "Use
Drupal Canvas" checkbox is checked, in order to rebuild every theme region from
the site's current classic block layout. For each block, it builds the
component's `inputs` from the block's raw `settings`, stripping only two known
keys:
```php
// \Drupal\canvas\Entity\PageRegion::createFromBlockLayout()
'inputs' => \array_diff_key($block->get('settings'), \array_flip([
// Remove these as they can be calculated and hence need not be
// stored.
'id',
'provider',
])),
```
However, `context_mapping` is also a standard key that Drupal core writes onto
**any** block's `settings` once it is saved through the Block Layout UI, as soon
as the block plugin implements `ContextAwarePluginInterface` and declares at
least one context definition — every `BlockBase` subclass implements this
interface, and `BlockBase::blockForm()`/`blockSubmit()` capture the assignment
unconditionally (see `Drupal\Core\Block\BlockBase::blockForm()` /
`ContextAwarePluginTrait::setContextMapping()`). This is extremely common for
Views blocks whose display has a contextual filter with an entity/numeric
validator — even if the mapping ends up empty (`context_mapping: { }`) because
nothing was actually mapped, or because the validator has since been changed.
Canvas's own component input schema for these components does not recognize
`context_mapping` as a supported key, so
`$page_region->getTypedData()->validate()` returns a
"'context_mapping' is not a supported key" violation, which trips the
`assert()` — and because PHP assertions are commonly enabled outside of strict
production tuning, this surfaces as an uncaught fatal error rather than a
graceful validation message.
## Steps to reproduce
1. Enable Drupal Canvas for a theme with at least one `PageRegion` entity
already created.
2. Place a Views block (any view with a block display that has a contextual
filter using an "Entity" or "Numeric" argument validator) into any region of
that theme, and save it at least once through the Block Layout UI (this is
what causes `context_mapping` to be persisted into the block's `settings`,
even as an empty array).
3. Go to `admin/appearance/settings/<theme>` and save the form (e.g. by
changing the logo).
4. Observe the fatal error / white screen instead of a successful save.
## Proposed resolution
Strip `context_mapping` from the block settings the same way `id` and
`provider` are already stripped in `PageRegion::createFromBlockLayout()`, since
it is calculated block-placement metadata, not a genuine component input:
```php
'inputs' => \array_diff_key($block->get('settings'), \array_flip([
// Remove these as they can be calculated and hence need not be
// stored.
'id',
'provider',
'context_mapping',
])),
```
This mirrors the existing rationale in the surrounding comment: `context_mapping`
is block-placement plumbing that Canvas's component input schema doesn't (and
arguably shouldn't need to) model, and it has no effect on rendering here since
affected Views blocks resolve their contextual filter value independently via
the view's own `argument_default` plugin when no argument is otherwise
provided.
A broader fix might also want to more gracefully surface *any* future case of a
strippable/unsupported settings key hitting this `assert()` — e.g. downgrading
it to a logged validation error with details, rather than an uncaught
`AssertionError`, so the failure mode for the next unsupported key is a
readable error instead of a blank fatal.
issue