Major error on content with required by role

Created on 14 January 2025, 3 months ago

Problem/Motivation

Saving content is throwing white screen of death with the following error:

TypeError: Drupal\required_api\Plugin\Required\RequiredDefault::isRequired(): Return value must be of type bool, array returned in Drupal\required_api\Plugin\Required\RequiredDefault->isRequired() (line 26 of modules/contrib/required_api/src/Plugin/Required/RequiredDefault.php).
Drupal\required_api\RequiredApiFormErrorHandler->handleFormErrors(Array, Object) (Line: 199)
Drupal\Core\Form\FormValidator->finalizeValidation(Array, Object, 'node_events_edit_form') (Line: 119)
Drupal\Core\Form\FormValidator->validateForm('node_events_edit_form', Array, Object) (Line: 593)
Drupal\Core\Form\FormBuilder->processForm('node_events_edit_form', Array, Object) (Line: 326)
Drupal\Core\Form\FormBuilder->buildForm(Object, Object) (Line: 73)
Drupal\Core\Controller\FormController->getContentResult(Object, Object) (Line: 39)
Drupal\layout_builder\Controller\LayoutBuilderHtmlEntityFormController->getContentResult(Object, Object)
call_user_func_array(Array, Array) (Line: 123)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() (Line: 638)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 121)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext(Array, Array) (Line: 97)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() (Line: 181)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 76)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 53)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 28)
Drupal\Core\StackMiddleware\ContentLength->handle(Object, 1, 1) (Line: 32)
Drupal\big_pipe\StackMiddleware\ContentLength->handle(Object, 1, 1) (Line: 116)
Drupal\page_cache\StackMiddleware\PageCache->pass(Object, 1, 1) (Line: 90)
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: 36)
Drupal\Core\StackMiddleware\AjaxPageState->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\StackedHttpKernel->handle(Object, 1, 1) (Line: 741)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)

Steps to reproduce

Try to save any content that has required by role in use

🐛 Bug report
Status

Active

Version

3.0

Component

Code

Created by

🇨🇦Canada robbdavis

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

Merge Requests

Comments & Activities

  • Issue created by @robbdavis
  • 🇨🇦Canada robbdavis

    Forced to roll back `drupal/required_api (3.0.0-beta1 => 2.1.0)`

    And `drupal/required_by_role (2.0.0-beta2 => 1.3.0)`

    Rolling back fixes for now.

  • 🇨🇦Canada robbdavis

    I should add that this also broke the required by role functionality as well. On the editpage of the node, fields that should not have been required for admin were showing as required.

  • 🇧🇪Belgium dieterholvoet Brussels

    That's not right, Drupal\Core\Field\FieldDefinitionInterface::isRequired() is never supposed to return an array:

    /**
     * Returns whether the field can be empty.
     *
     * If a field is required, an entity needs to have at least a valid,
     * non-empty item in that field's FieldItemList in order to pass validation.
     *
     * An item is considered empty if its isEmpty() method returns TRUE.
     * Typically, that is if at least one of its required properties is empty.
     *
     * @return bool
     *   TRUE if the field is required.
     *
     * @see \Drupal\Core\TypedData\Plugin\DataType\ItemList::isEmpty()
     * @see \Drupal\Core\Field\FieldItemInterface::isEmpty()
     * @see \Drupal\Core\TypedData\DataDefinitionInterface:isRequired()
     * @see \Drupal\Core\TypedData\TypedDataManager::getDefaultConstraints()
     */
    public function isRequired();

    Could you share the YAML content of the field config that's failing? Should be a field on the events node type, one with an array instead of a boolean in its required key.

  • 🇧🇪Belgium dieterholvoet Brussels

    I should add that this also broke the required by role functionality as well. On the editpage of the node, fields that should not have been required for admin were showing as required.

    Maybe that's caused by this problem, but I should note that fields that are conditionally being made (not) required now always show the red asterisk, even though no validation error is shown when submitting the form. This was a side effect of a big, necessary refactor of the module. I thought it was acceptable at the time, but if you don't like the way that works, feel free to open a separate issue and we can try to make that a configurable option. Shouldn't be too hard, it's only a visual thing after all. Let's wait until we figure out this issue first though.

  • 🇨🇦Canada robbdavis

    Thanks for the reply. For now I'm downgraded back to the previous version. When i get a chance, I'll try upgrading again on my local and post debugging info/ideas here.

  • First commit to issue fork.
  • 🇬🇧United Kingdom jollysolutions

    changing the isRequired from bool to mixed removed the error for me, I am unsure why some field definitions are arrays instead of bools

  • 🇬🇧United Kingdom jollysolutions

    jollysolutions changed the visibility of the branch 3499720-major-error-on to hidden.

  • Merge request !17Resolve #3499720 → (Closed) created by Unnamed author
  • Pipeline finished with Success
    3 months ago
    Total: 149s
    #404891
  • 🇧🇪Belgium dieterholvoet Brussels

    I’m not changing it to mixed, it’s supposed to be a boolean. Maybe some older version of this module wrote an array to that value and because of the absence of type hints, that was never a problem, but it’s becoming a problem. So if someone could share what exactly is in the array, I can add an update hook that corrects these field definitions.

  • 🇬🇧United Kingdom jollysolutions

    They are blank arrays in config. I tried to set them to FALSE and do a config import but on the very next export they change back to empty arrays

  • 🇬🇧United Kingdom jollysolutions
    langcode: en
    status: true
    dependencies:
      config:
        - field.storage.user.field_phone_number
      module:
        - disable_field
        - required_api
        - telephone
        - telephone_validation
        - user
    third_party_settings:
      required_api:
        required_plugin: default
        required_plugin_options: {  }
      disable_field:
        add_disable: none
        edit_disable: none
      telephone_validation:
        format: 0
        country: {  }
    id: user.user.field_phone_number
    field_name: field_phone_number
    entity_type: user
    bundle: user
    label: 'Phone Number'
    description: 'Please enter the number with +44 at the front and omitting the leading zero for example +447700900000 instead of 07700900000.'
    required: {  }
    translatable: false
    default_value: {  }
    default_value_callback: ''
    settings: {  }
    field_type: telephone

    an example of a config field where this happens

  • 🇧🇪Belgium dieterholvoet Brussels

    I went through older versions of the module, but I don't see where an array would have been assigned to the required property. Was your site migrated from Drupal 7?

    Either way, I'll write an update hook that converts non-boolean values in the required property to booleans. Shouldn't change anything about the current behaviour.

  • 🇧🇪Belgium dieterholvoet Brussels

    This might be because of Drupal 11 config validation, but I can't even assign an empty array to the required key when editing the config yaml. Drupal seems to overwrite it after importing. I'll write an update hook anyway, but I won't be able to test it myself.

  • 🇬🇧United Kingdom jollysolutions

    jollysolutions changed the visibility of the branch 3499720- to hidden.

  • Merge request !18Resolve #3499720 "Temp fix" → (Open) created by Unnamed author
  • 🇬🇧United Kingdom jollysolutions

    jollysolutions changed the visibility of the branch 3499720-mixed_so_it_works_for_now to hidden.

  • Pipeline finished with Success
    2 months ago
    Total: 146s
    #410255
  • 🇧🇪Belgium dieterholvoet Brussels

    dieterholvoet changed the visibility of the branch 3499720-temp_fix to hidden.

  • Merge request !19Add update hook to fix configs → (Closed) created by dieterholvoet
  • 🇧🇪Belgium dieterholvoet Brussels

    I created a MR with an update hook that fixes your configs. Do not forget to export config after running it. Could you let me know if that changes anything @jollysolutions @robbdavis?

  • 🇬🇧United Kingdom jollysolutions

    I added your patch and drush updb. The error still occurs and the exported config did not change. :(

  • 🇧🇪Belgium dieterholvoet Brussels

    What message was logged after running the update hook? Did it say it updated any config, even though no changes were exported?

    The only other fix I can think of is manual. Can you try and re-save the config without changing anything by using the Field UI? Or if that doesn’t work, can you try manually replacing the empty array with a Boolean value in the yml file and importing your changes?

    If that doesn’t fix the problem, I have no idea what’s causing it. I can tell you Required API is not causing the problem, it’s merely exposing it. Once core adds a return type to Drupal\Core\Field\FieldDefinitionInterface::isRequired(), which is only a matter of time, your project will start to break in a lot more places.

    I recommend you try and find out what other module might be causing this issue instead of applying the workaround you added in a MR, because it’s not a permanent fix. It sounds like maybe there’s an event subscriber or entity hook altering the value before it’s being saved.

  • 🇧🇪Belgium dieterholvoet Brussels

    Looks like someone found the issue: 🐛 TypeError: RequiredDefault::isRequired(): Return value must be of type bool, array returned Active . I'm moving this to the Required by role issue queue and closing the other one as a duplicate.

  • 🇧🇪Belgium dieterholvoet Brussels

    I fixed the update hook that caused the issue and added a new update to fix the wrong config. One problem: the original value of the required property is lost, so to be on the safe side I'm marking all affected fields as required. The config ids of said fields are logged and should be reviewed manually to make sure they actually need to be required.

  • Pipeline finished with Skipped
    about 2 months ago
    #431325
  • Automatically closed - issue fixed for 2 weeks with no activity.

Production build 0.71.5 2024