Problem/Motivation

Drupal\field_ui\Form\EntityDisplayFormBase::copyFormValuesToEntity() assumes that every field listed in $form['#fields'] is also present in $form_values['fields'].

That assumption is not always valid during Field UI multistep/AJAX operations using limited validation. In an intermediate rebuild, FormState may intentionally contain only the values for the component currently being edited.

Core nevertheless iterates over all entries in $form['#fields'] and dereferences the corresponding values unconditionally:

foreach ($form['#fields'] as $field_name) {
  $values = $form_values['fields'][$field_name];

This results in warnings such as:

Warning: Undefined array key "created" in Drupal\field_ui\Form\EntityDisplayFormBase->copyFormValuesToEntity()

Warning: Trying to access array offset on null in Drupal\field_ui\Form\EntityDisplayFormBase->copyFormValuesToEntity()

The same assumption exists in the loop handling $form['#extra'].
This can be reproduced with Field Group, but the issue is not specific to Field Group. The underlying problem is that copyFormValuesToEntity() does not tolerate a valid partial submitted values tree during multistep Field UI operations.

Steps to reproduce

Tested with Drupal 11.4.8.

  1. Install and enable Field Group.
  2. Create a content type.
  3. Add at least one configurable field, for example a text field.
  4. Go to Manage form display.
  5. Click the settings cog for the Title base field.
  6. Observe that the settings form opens without warnings.
  7. Add a Field Group to the form display.
  8. Put one or more fields into that group and save.
  9. Return to Manage form display.
  10. Click the settings cog for the Title field again.

PHP warnings are emitted from EntityDisplayFormBase::copyFormValuesToEntity().
The issue is especially easy to reproduce with base fields such as title.

Instrumentation in copyFormValuesToEntity() shows multiple calls during the multistep request. A normal/full call contains all fields. However, an intermediate call when opening the Title widget settings contains only title, langcode, status, uid, while $form['#fields'] still contains all the remaining fields. Therefore fields are absent from $form_values['fields'] during that intermediate rebuild, but core then attempts to access them anyway. A later rebuild contains the complete values tree again.

Proposed resolution

Skip display components that are not present in the current submitted values.
For regular fields:

foreach ($form['#fields'] as $field_name) {
  if (!isset($form_values['fields'][$field_name])) {
    continue;
  }

  $values = $form_values['fields'][$field_name];

  // Existing processing.
}

Apply the same guard to the #extra loop:

foreach ($form['#extra'] as $name) {
  if (!isset($form_values['fields'][$name])) {
    continue;
  }

  if ($form_values['fields'][$name]['region'] == 'hidden') {
    $entity->removeComponent($name);
  }
  else {
    $entity->setComponent($name, [
      'weight' => $form_values['fields'][$name]['weight'],
      'region' => $form_values['fields'][$name]['region'],
    ]);
  }
}

If a component is absent from the current limited-validation submission, it should be left unchanged. With these guards in place:

  • the PHP warnings disappear;
  • the base-field widget settings form opens correctly;
  • configurable-field widget settings continue to work;
  • the later rebuild again contains the full field values tree;
  • the form display remains functional.

The change only skips components that were not submitted in the current partial form state.

Remaining tasks

  • Add automated test coverage for partial $form_values['fields'].
  • Cover both $form['#fields'] and $form['#extra'].
  • Confirm behavior for Manage form display and Manage display.
  • Confirm whether isset() or array_key_exists() is preferred.
  • Add a current merge request against the supported core branch.

Related issues

#3188588: EntityDisplayFormBase (Form Display) throws Notices when opening field settings for Media Library Widget
#3188588 reported the same underlying failure in copyFormValuesToEntity() and proposed essentially the same defensive guard: skip processing when the corresponding field values are absent. That issue was later closed as a duplicate of #3134554.

#3134554: Media fields with Media Library form widget trigger PHP 'Notice: Undefined index'
The root cause in #3134554 was specific to MediaLibraryWidget::settingsForm(), which returned the incoming form instead of only its own settings elements. The accepted resolution was therefore Media Library-specific, rather than adding a general defensive check to EntityDisplayFormBase.

The present issue has a different reproducer and does not require Media Library. Notably, #3188588 also received a later report in 2024 of the same warnings affecting Paragraphs and custom entities, with the reporter confirming that the old defensive patch from #3188588 resolves the issue.

Issue fork drupal-3631593

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

jordik created an issue. See original summary.

jordik’s picture

Issue summary: View changes
jordik’s picture

Issue summary: View changes
jordik’s picture

Issue summary: View changes

jordik’s picture

[MR !17491] is ready for review.

The regression test fails on unpatched core with PHP warnings and corruption of omitted component configuration, and passes with the proposed guards for regular fields and `#extra` components.

jordik’s picture

Status: Active » Needs review
quietone’s picture

Version: 11.x-dev » main

Issue are fixed on the development branch first, which is 'main'.