Hi,

I got an Ajax error message on a "node" form, after I clicked to an "Add more" button by an unlimited (address) field.

PHP error message from the error_log:

mod_fcgid: stderr: Recoverable fatal error: Argument 1 passed to Drupal\\Core\\Form\\
FormState::setError() must be of the type array, null given, called in /var/www/clients/client1/web137/web/core/lib/Drupal/Core/Field/WidgetBase.php on line 448 and defined in
/var/www/clients/client1/web137/web/core/lib/Drupal/Core/Form/FormState.php on line 1157

I attach a patch file to fix this problem, I hope it can be apply. :) Thank you!

Comments

Lóna Lore created an issue. See original summary.

lonalore’s picture

StatusFileSize
new754 bytes
nickdickinsonwilde’s picture

+++ b/core/lib/Drupal/Core/Field/WidgetBase.php
@@ -444,7 +444,7 @@ public function flagErrors(FieldItemListInterface $items, ConstraintViolationLis
-            if ($error_element !== FALSE) {
+            if (is_array($error_element)) {

Maybe a simple boolean test rather than is_array() or strict would be better - is_array is IIRC around 4X more expensive than isset quite a bit worse compared to a simple if(). I think just using if ($error_element) might be good enough. True less still open to a wrong but it should always be False or an array so... (to be clear I'm not saying that *should* be the fix but thought I'd mention it).

lonalore’s picture

StatusFileSize
new744 bytes

@NickWilde, thank you for your answer, as you mentioned, I modified the patch file. :) I tested, it does the trick. :)

longwave’s picture

How do I reproduce this? If this needs http://drupal.org/project/address then this is likely a bug in that module.

nickdickinsonwilde’s picture

@longwave: I haven't yet repro/tested it but it shouldn't fatal error if passed NULL instead of FALSE - unless it gives a reasonable error message.

lonalore’s picture

Yes, to reproduce this bug you need to install address module. I didn't try to reproduce it with using core field types, so it is possible that address module fault.

amateescu’s picture

Project: Drupal core » Address
Version: 8.0.0 » 8.x-1.x-dev
Component: field system » Code
Status: Needs review » Postponed (maintainer needs more info)

Also tried to reproduce this and I couldn't. Can you please provide more detailed information about every field of that node form and how they're configured?

Just closed a duplicate as well: #2602004: Having a required integer field on the same entity breaks AJAX

subhojit777’s picture

subhojit777’s picture

Status: Postponed (maintainer needs more info) » Needs review
subhojit777’s picture

The patch in #2 fixes the issue.

amateescu’s picture

The steps in #9 are exactly the ones I tried and selecting a country does not trigger any error, the form is updated with the correct address fields via AJAX.

Are there any other modules that you have installed besides Composer manager and Address? Or is it possible for you to provide some kind of test access to a Drupal instance where this problem can be reproduced?

subhojit777’s picture

@amateescu Just confirming - did you executed these two commands php modules/composer_manager/scripts/init.php, composer drupal-update after downloading composer_manager. And composer_manager does not needs to be installed.

Weird that you are not able to reproduce the problem :/

Apart from the steps you don't have to install any other modules, not even commerce module. I will try to setup a simplytest.me instance.

subhojit777’s picture

I cannot configure a simplytest.me instance, address module requires composer package update. You have to test it manually :( Let's see what others say.

amateescu’s picture

@subhojit777, of course I ran the composer manager init and and the drupal-udpate command, I wouldn't have been able to install the Address module otherwise :)

subhojit777’s picture

@amateescu just confirming :)

banacan’s picture

I have the same problem (running 8.0.2) but I am using multiple taxonomy terms not addresses. When I click "Add another item" nothing happens, but in the logs it shows as:

Recoverable fatal error: Argument 1 passed to Drupal\Core\Form\FormState::setError() must be of the type array, null given, called in /Users/fred/vhosts/ddclab/core/lib/Drupal/Core/Field/WidgetBase.php on line 446 and defined in Drupal\Core\Form\FormState->setError() (line 1156 of /Users/fred/vhosts/ddclab/core/lib/Drupal/Core/Form/FormState.php).

This is the code if I click Location in the log detail:

[{"command":"add_css","data":"\u003Clink rel=\u0022stylesheet\u0022 href=\u0022http:\/\/ddclab:8888\/sites\/default\/files\/css\/css_WoUSDQq02piOhfQKmkZkre5BurnnMpHpdP6QO8aYdt8.css?o0t394\u0022 media=\u0022all\u0022 \/\u003E\n"},{"command":"insert","method":"replaceWith","selector":null,"data":"\n \u003Cdiv role=\u0022contentinfo\u0022 aria-label=\u0022Error message\u0022 class=\u0022messages messages--error\u0022\u003E\n \u003Cdiv role=\u0022alert\u0022\u003E\n \u003Ch2 class=\u0022visually-hidden\u0022\u003EError message\u003C\/h2\u003E\n An unrecoverable error occurred. The uploaded file likely exceeded the maximum file size (32 MB) that this server supports.\n \u003C\/div\u003E\n \u003C\/div\u003E\n \n","settings":null}]

Hope this helps.

bojanz’s picture

Category: Bug report » Support request
Status: Needs review » Active

Whatever this is, it's a core bug. Don't see what Address can do to prevent it.

banacan’s picture

I agree, though I'm speaking of my own case which has nothing to do with Address. I wanted to test this issue a bit more so I created another content type with just a title, body, and two unlimited fields: one taxonomy and one integer. When entering the first record I was able to add additional items in the taxonomy list just fine. But the next record didn't let me add more than one taxonomy. So I moved on to the integer field and I was able to add as many as I liked. I went back to the taxonomy field and tried again, but this time I was able to add more. I have tested this multiple times and it continues to be a problem. I can enter only one taxonomy item, but if I move on to other fields and later come back to the taxonomy field, then I can add more items. This is clearly a bug of some sort.

morsok’s picture

Status: Active » Needs review

I have no idea what caused this, but the patch solved the error in my case.

bojanz’s picture

Status: Needs review » Active

There is no Address module patch in this issue.

rolfmeijer’s picture

This seems to be the related core issue: #2614250: Number widget validation can break AJAX actions

mcdruid’s picture

I got here via #2691287: Ajax error when changing country value

There may be a core issue here too, but I think there is something address could change.

The problem's already been described in this issue; core's WidgetBase class has a flagErrors method which does this:

          foreach ($delta_violations as $violation) {
            // @todo: Pass $violation->arrayPropertyPath as property path.
            $error_element = $this->errorElement($delta_element, $violation, $form, $form_state);
            if ($error_element !== FALSE) {
              $form_state->setError($error_element, $violation->getMessage());
            }
          }

The API docs for errorElement say it should return:

array|bool The element on which the error should be flagged, or FALSE to completely ignore the violation (use with care!).

However, address's current implementation does this:

   public function errorElement(array $element, ConstraintViolationInterface $violation, array $form, FormStateInterface $form_state) {
     return NestedArray::getValue($element, $violation->arrayPropertyPath);
   }

...where getValue will (perhaps rather strangely) currently return null rather than false if the element/key's not found.

There will be several different ways you could do this, but checking for that null and returning false instead per the API resolves the problem with AJAX errors when switching between certain countries (e.g. USA and Zimbabwe if you want to reproduce).

e.g.

  public function errorElement(array $element, ConstraintViolationInterface $violation, array $form, FormStateInterface $form_state) {
    $element = NestedArray::getValue($element, $violation->arrayPropertyPath);
    return (!is_null($element)) ? $element : FALSE;
  }

Here's a patch for the address module which does that.

To even better adhere to the API, you could perhaps check with is_array and return FALSE if not.

anavarre’s picture

Status: Active » Needs review
bc’s picture

The patch in #23 works for me.

NB I only run into this bug when on an Acquia server and was not able to reproduce it when developing locally with php-cli & drush.

mcdruid’s picture

Just confirming that I was able to reproduce the error on a non-Acquia environment (Ubuntu 14.04 running stock PHP 5.5 as mod_php, FWIW).

They key steps to make the problem happen repeatedly were to switch between particular countries; it looks like the problem doesn't arise if the form elements don't change. We found switching between USA and Zimbabwe reproduced the error reliably (but only in one direction - IIRC it was switching from Zimbabwe to the USA, but I can't be 100% sure I'm remembering that right).

mcdruid’s picture

Not yet sure whether it's a problem being introduced by an incorrect patch in #2745491: ImageWidget::validateRequiredFields() produces a PHP Warning message if triggering element is a non-button, but with the 2745491-7.patch in place I see more Warnings / Notices relating to validation of the address field(s) e.g.

Notice: Undefined index: #parents in Drupal\Core\Form\FormState->setError() (line 1152 of ...docroot/core/lib/Drupal/Core/Form/FormState.php).

Warning: implode(): Invalid arguments passed in Drupal\Core\Form\FormState->setError() (line 1152 of ...docroot/core/lib/Drupal/Core/Form/FormState.php).

These seem to come about when the $element passed to AddressDefaultWidget::errorElement does include an array with a key which matches the propertyPath of the $violation, but this array is just:

'#value' = '',
'#validated' = true

...which is obviously not a valid element to pass to FormState->setError() .

Only local images are allowed.

It's not hard to check for this sort of problem before returning the $element and thus avoid the errors e.g.

   public function errorElement(array $element, ConstraintViolationInterface $violation, array $form, FormStateInterface $form_state) {
    $element = NestedArray::getValue($element, $violation->arrayPropertyPath);
    return (is_array($element) && isset($element['#parents'])) ? $element : FALSE;

...I'm just not quite sure if this is necessary yet. Noting here in case this comes back if / when the ImageWidget::validateRequiredFields issue is fixed.

segovia94’s picture

The patch in #23 works for me.

My issue was when selecting a country, selecting None, and then trying to select a country again.

gapple’s picture

Category: Support request » Bug report
StatusFileSize
new712 bytes

Encountered this issue with the steps in #28 as well.

The patch in #23 resolves the issue, just a bit of a style change to use a ternary operator instead.

andrej galuf’s picture

Confirming that #23 resolves the issue at hand. I've had the same problem as #28 - when I selected - None - and then the country again, the Widget's Ajax crashed.

gapple’s picture

Status: Needs review » Reviewed & tested by the community

I think there's been enough feedback to RTBC this issue.

mcdruid’s picture

FWIW I'm not sure about using the simple ternary operator as per #29

It'll probably work, but the problem here is specifically that null is sometimes returned; I think it's less vague to specifically check for the null (or perhaps to specifically check for an array, as mentioned).

Here's a new patch which does the latter (checks for an array, and returns FALSE if $element is anything else). I think that's the closest to the API (but it's barely any different to the patch in #23).

Any of these approaches should resolve the issue though.

blanca.esqueda’s picture

Confirming that #32 resolves the issue. I've had the same problem as #28 and #30

- when I selected - None - and then the country again, the Widget's Ajax crashed.

dww’s picture

+1 for patch #32. Confirmed that setting country to -None- and then trying to set it to anything else results in the AJAX crashes described here. Patch #32 resolves the issue and allows users to go from -None- to anything else.

I also prefer being explicit with that's happening, instead of using the ternary operator from #29.

I don't feel strongly about is_array() from #32 vs. !is_null() from #23. is_array() is slightly slower, but this code isn't exactly in the critical path where micro optimizations like that would really matter.

Thanks,
-Derek

dww’s picture

Status: Reviewed & tested by the community » Needs work

Needs reroll now that #2689089: Define a form element type "address" went in.

  • bojanz committed bca416e on 8.x-1.x authored by mcdruid
    Issue #2619878 by lonalore, mcdruid, gapple: Recoverable fatal error:...
bojanz’s picture

Status: Needs work » Patch (to be ported)

I'm pretty sure there's a deeper problem here (cause why wouldn't there be an error element?), but there's no harm in following the actual expected return value.
Rerolled and committed #32. Thanks.

bojanz’s picture

Status: Patch (to be ported) » Fixed

D'oh.

amateescu’s picture

The deeper problem is the one linked in #34 ;)

Status: Fixed » Closed (fixed)

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