Problem/Motivation

Users see the following error when a Name component is rendered as a select and no blank option is present (no -- line in field options), or when #options is not keyed with _none (e.g. programmatic name elements):

Warning: Undefined array key "_none" in name_element_render_component() (line 467 of /xxx/modules/contrib/name/name.module)

Root cause: name_element_render_component() reads $element['#options']['_none'] without ensuring the key exists. PHP 8+ raises an undefined array key warning.

Steps to reproduce

As per the help text for a Name field’s Title or Generational options:

Prefix a line using -- to specify a blank value text.

  1. Add a Name field to a content type.
  2. Set the component to a drop-down for Title or Generational.
  3. Provide no empty-value line (no -- line) in the options list.

screenshot instructing to remove the blank value option from the title component field select options list.

Additional steps to reproduce

With the following module enabled, visit /my-custom-form.

# my_custom.info.yml
name: 'My Custom'
type: module
description: 'Add an example Name field form'
core_version_requirement: ^10 || ^11
package: Debugging
dependencies:
  - drupal:name
# my_custom.routing.yml
my_custom.form:
  path: '/my-custom-form'
  defaults:
    _form: '\Drupal\my_custom\Form\MyCustomForm'
    _title: 'My Custom Name Form'
  requirements:
    _permission: 'access content'
// @file src/Form/MyCustomForm.php

namespace Drupal\my_custom\Form;

use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;

/**
 * Custom form with Name field.
 */
class MyCustomForm extends FormBase {

  public function getFormId(): string {
    return 'my_custom_form';
  }

  public function buildForm(array $form, FormStateInterface $form_state): array {
    $form['person'] = [
      '#type' => 'name',
      '#title' => $this->t('Person'),
      '#name_settings' => [
        'minimum_components' => ['family', 'given'],
      ],
    ];

    $form['actions']['submit'] = [
      '#type' => 'submit',
      '#value' => $this->t('Submit'),
    ];
    return $form;
  }

  public function submitForm(array &$form, FormStateInterface $form_state): void {
    // No-op.
  }

}

Proposed resolution

  • At render time, treat the first option whose label starts with -- as the empty placeholder (same rule as the field UI help text). Map it to #empty_value / #empty_option for core’s select element.
  • Normalize remaining options to stable label => label where needed so values stay consistent when options were numerically keyed or translated.
  • Never access ['#options']['_none'] unless that key is known to exist.
  • Add kernel test coverage for option normalization (see MR).

Follow-up: Longer term, consolidate “leading -- means empty” in one place so the renderer does not depend on a magic _none key that can disappear after processing. Discussion: #comment-16332465.

Remaining tasks

  • Review and merge the MR to 8.x-1.x.
  • Confirm automated tests pass on the MR pipeline.
  • RTBC when verified.

User interface changes

None expected for correctly configured fields. Select behavior should match the existing -- blank-line convention.

Introduced terminology

None.

API changes

None. Internal form element assembly for select components only.

Data model changes

None.

Release notes snippet

Fixed a PHP 8+ warning (Undefined array key "_none") when rendering Name select components without a configured blank option or when options are not keyed as _none.


Related: Not a duplicate of #3491471 (literal _none stored). Validation treating _none as empty: #3555879 (separate issue).

Issue fork name-3491962

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

promes created an issue. See original summary.

sayan_k_dutta’s picture

@promes, can you please provide the steps to reproduce the issue.
I used the name field and created content using 1.x-dev version but found no warnings.

promes’s picture

I have a name field where a title is required. The '-- --' option is not present, but only other options. So the [_none] => -- is not present as select option when function name_element_render_component() is called.

I was wrong. Line 467 should read:
if (isset($element['#options']['_none']) && $element['#options']['_none']) {

deepali sardana’s picture

Assigned: Unassigned »
sourabhsisodia_’s picture

I think the issue is a duplicate of this Issue

deepali sardana’s picture

Assigned: » Unassigned
Status: Active » Needs review
StatusFileSize
new603 bytes

I have created the patch pleas review it

megachriz’s picture

@sourabhsisodia
This looks related to #3491471: Literal "_none" value saved for select fields, but this issue is not a duplicate of that one. This issue is about a situation where the option "_none" is not defined. That other issue is about literally saving "_none" in the database when that option is selected.

bramdriesen’s picture

Status: Needs review » Needs work

@deepali sardana Like mentioned on many issues already to you. Patch workflows are deprecated. Please create a MR.

shivam_tiwari made their first commit to this issue’s fork.

shivam_tiwari’s picture

Status: Needs work » Needs review

bluegeek9 made their first commit to this issue’s fork.

bluegeek9 changed the visibility of the branch 8.x-1.x to hidden.

liam morland made their first commit to this issue’s fork.

jcandan’s picture

Thanks for the fix in MR 27 — it resolves the warning.

However, with the current patch, the warning goes away because PHP no longer tries to access a missing key — but the <select> still doesn’t get #empty_value or #empty_option properties, since those are only set when the key is exactly '_none' .

To make it fully robust, the renderer could also handle empty options keyed as 0 or '', which are common in Drupal forms:

if ($matches = array_intersect_key($element['#options'], array_flip(['_none', 0, '']))) {
  $empty_key = array_key_first($matches);
  $element['#empty_value']  = '_none';
  $element['#empty_option'] = $matches[$empty_key];
  unset($element['#options'][$empty_key]);
}

That way, selects with numeric or empty-string keys get both the warning fix and correct empty-option behavior.

jcandan’s picture

Assigned: Unassigned » jcandan
jcandan’s picture

Status: Needs review » Needs work
jcandan’s picture

Assigned: jcandan » Unassigned
Status: Needs work » Needs review
jcandan’s picture

Status: Needs review » Needs work

I'm not totally sure yet; I need to conduct some testing, but I may have identified a related validation gap that could explain why this issue passed basic tests.

When a component renders as a <select> and the site builder provides an empty option (prefixed with --), Name normalizes that internally to a _none key. This issue (#3491962) focuses on the renderer assuming _none exists, which led to undefined-index notices.

However, once _none does exist consistently, the current validation logic in name_element_validate() (and related helpers) will treat _none as a non-empty string and therefore consider that component filled. This causes any downstream logic that checks for emptiness or required components to think the user entered data when they have not.

  foreach (_name_translations() as $key => $title) {
    if (isset($labels[$key]) && !empty($item[$key])) {
      $item_components[$key] = 1;
    }

A potential fix I've applied:

  foreach (_name_translations() as $key => $title) {
    if (!isset($labels[$key])) {
      continue;
    }
    $value = $item[$key] ?? NULL;

    // If this component renders as a <select>, the placeholder value '_none'
    // must be treated as empty.
    $is_select = (($element['#components'][$key]['type'] ?? NULL) === 'select');
    if ($is_select && $value === '_none') {
      $value = '';
    }

    if ($value !== NULL && $value !== '') {
      $item_components[$key] = 1;
    }

This normalizes _none back to empty before validation counts the component.

Not yet confirmed, but this may have masked test coverage—previously, the missing _none option meant selects simply skipped over this case, so the incorrect “non-empty” behavior never appeared. With #3491962’s fix in place, this could now surface.

We may also want to ensure there’s better test coverage for empty-value handling in general—particularly for select-based components using the -- placeholder pattern—so that cases like this don’t continue to fly under the radar once _none normalization is fixed.

More testing to confirm is needed.

jcandan’s picture

Assigned: Unassigned » jcandan
Issue summary: View changes

On the _none normalization logic:

Re-reading #3 got me to look closer and I realized 0 might be a valid option, and not a desired empty option!

It looks like the 0 key I was seeing wasn’t coming from any real, admin-entered configuration, but from how the test fixtures (and some programmatic field setups) defined #options without a proper -- blank value line:

$element = [
  'title' => [
    '#type' => 'select',
    '#title' => 'Title', 
    '#options' => ['Dr.' => 'Dr.', 'Mr.' => 'Mr.'],

Per the field UI help text —

“Prefix a line using -- to specify a blank value text.”
— only those prefixed lines should produce a _none empty key. If no -- line exists, the 0th item is a valid choice and shouldn’t be promoted to _none.

So, my attempt at a broader normalization of ['_none', 0, ''] is too aggressive. The original, simpler guard —

if (isset($element['#options']['_none']) && $element['#options']['_none']) {
  ...
}

— might actually be the correct way to address this, and the 0 case I was seeing may have been an artifact of our tests.

That said, I am still looking at whether #19 applies.

Updated issue summary to reflect the clarified steps to reproduce from #3.

jcandan’s picture

Issue summary: View changes
StatusFileSize
new19.87 KB
jcandan’s picture

Issue summary: View changes
jcandan’s picture

#19 does not apply here. A new issue has been created to address the concern at #3555879: Fix validation logical condition considers _none a non-empty component.

I am still testing concerns brought up in #20.

jcandan’s picture

Issue summary: View changes

I now recall how this became a blocker for #3552451: Required state incorrectly marks non-minimum components as required.

When creating a form with a Name field via the FormBase class, I get the warning.

It was a blocker because the warnings were making it so that the FunctionalJavascript tests were unable to toggle a #states target field:

    // Gate control.
    $form['gate'] = [
      '#type' => 'checkbox',
      '#title' => $this->t('Gate'),
      '#description' => $this->t('Make Name required when ON (or OFF for unchecked variants)'),
      '#default_value' => 0,
    ];

    $form['person'] = [
      '#type' => 'name',
      '#title' => $this->t('Person'),
      // Ensure predictable minimum components for assertions.
      '#name_settings' => [
        // Force family & given to be the minimum components.
        'minimum_components' => ['family', 'given'],
      ],
      // Attach states with the chosen variant.
      '#states' => [
        'required' => [
          ':input[name="gate"]' => ['checked' => TRUE],
        ],
      ],
    ];

Updated steps to reproduce.

jcandan’s picture

Issue summary: View changes
jcandan’s picture

When stepping through the name_element_render_component(), I was able to capture these surprising differences.

Screenshot showing a simplified set of Title component select options:

screenshot showing the simple title select options

This is acquired when viewing a field configured through the UI. It shows the select options as key value pairs (e.g. <?php ['Mr.' => 'Mr.', 'Mrs.' => 'Mrs.']).

Screenshot showing an array of Drupal\Core\StringTranslation\TranslatableMarkup options:

screenshot showing the indexed array options

This is acquired when visiting the custom form detailed in the steps-to-reproduce. It shows the select options as a numbered indexed array of TranslatableMarkup elements representing each string value option.


That being said, it appears the idea of 0 being a _none value was a huge misstep on my part (thanks for nothing ChatGPT)!

What is not known is whether the option keys or the string values will actually be used for the select value. Does Drupal use the values of an #options array? I guess it does, thinking about it.

Digging into how we can adjust the logic to handle both scenarios.

jcandan’s picture

Issue summary: View changes
jcandan’s picture

I am adding a defensive normalization in the element build to cope with the fact that, by the time the Name component is rendered, the options array is no longer in the shape the options provider would normally return.

In our case the translated options came through as a numerically indexed list like [0 => '-- --', 1 => 'Mr.', 2 => 'Mrs.'] , so the renderer’s existing assumption that ['_none' => '…'] would be present was no longer valid.

We will do three things at render time:

  1. scans once for the first -- … entry and promotes it to #empty_option/#empty_value,
  2. keeps any subsequent -- … lines in the list (since Name allows those as section headers), and
  3. re-keys the remaining options to label => label so we don’t end up saving numeric values coming from a reindexed array.

This is intentionally a small, backwards-compatible band-aid at the point of failure; the longer-term fix will be to make the Name widget apply its leading -- means empty rule in a single place and to stop the renderer from depending on a special _none entry that can be lost by translation/reindexing.

jcandan’s picture

Assigned: jcandan » Unassigned
Status: Needs work » Needs review
jcandan’s picture

promes’s picture

The current 8.x-1.1 still has a bug:
Warning: Undefined array key "_none" in name_element_render_component() (line 470 of /xxx/web/modules/contrib/name/name.module)
The line reads:
if ($element['#options']['_none']) {
but should read:
if (isset($element['#options']['_none']) && $element['#options']['_none']) {

jcandan’s picture

Correct, @promes, this has not yet been merged, so 8.x-1.1 still has the bug.

The fix you've proposed is not complete (See #28).

If you are able to confirm MR !27 fixes the issue, please mark this as RTBC.

promes’s picture

I don't us a custom module. I use a regular name field, but require to select a title. With my latest patch the site works as expected.
In other sites I only name fields with '-- --' in the selection of a title. These sites are working without my patch.

bluegeek9’s picture

Issue summary: View changes
bluegeek9’s picture

Status: Needs review » Fixed
//www.flaticon.com/free-icons/thank-you Thank you for your contribution! Your continued support makes this project sustainable.
There are multiple ways to show appreciation for the work contributed to this project including:

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.

Status: Fixed » Closed (fixed)

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