TypeError: Argument 2 passed to _captcha_insert_captcha_element() must be of the type array, null given, called in /src/web/modules/contrib/captcha/captcha.module on line 169 in _captcha_insert_captcha_element()

This is causing an error on a site that I'm working on. _captcha_get_captcha_placement is returning null and then that is passed to _captcha_insert_captcha_element causing the error. It looks like all other places run a sanity check on the placement variable so I'm adding a patch that does the same thing.

Issue fork captcha-3075256

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:

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

kleinmp created an issue. See original summary.

kleinmp’s picture

cristiroma’s picture

I don't think the patch is good, if you add the verification then the form will not have CAPTCHA. I think the root of the problem is the _captcha_get_captcha_placement and that needs to be investigated why it's returning null.

We had a similar issue with mailchimp subscription block:

In captcha.inc:223

  // Query the placement map.
  if (array_key_exists($form_id, $placement_map)) {
    $placement = $placement_map[$form_id];
  }

In this our $placement_map[$form_id] = NULL for some reason but happened only in production. It went away after adding

if (FALSE) { } and then restore back. Some strange condition lead to $placement code being null (after a deployment)

pierre-nono’s picture

With the latest version (beta3), with the option -enabled_default enabled then it will try to implement on views exposed form.
Even if the views is an admin page and the option allow_on_admin_pages to false.
And if the user don't have the permission to skip Captcha, then it will make the bug happen.

TypeError: Argument 2 passed to _captcha_insert_captcha_element() must be of the type array, null given, called in /var/www/projets/k-et-b-entreprise/www/modules/contrib/captcha/captcha.module on line 224 in _captcha_insert_captcha_element() (line 325 of modules/contrib/captcha/captcha.inc). 

There are two points for me.
First the logic in captcha_form_alter() is wrong, I think.
Once it enter

  if (!$account->hasPermission('skip CAPTCHA')) {
   ...
 }

It never check again if we are on an admin page.

 if ( \Drupal::service('router.admin_context')->isAdminRoute() && !$config->get('allow_on_admin_pages') )

should also be tested at the begining of the function. And if return TRUE, then we don't go beyond.
I will try to give a patch soon.

Second, even if we manage that, I think we need an option, or something to avoid automatically trying to alter the views exposed form.

pierre-nono’s picture

Probably not a true fix for this issue, and more a work around it. But it's solved our problem (#4).

wundo’s picture

alfaguru’s picture

Rerolled patch for latest version of captcha.

Spokje’s picture

Looks like this is happening when the module can't find a place to put the captcha, which in my case was because my form had no button and an action on the form defined in an external JavaScript.

I've added a patch that, as a last resort after going through all the currently defined options, puts the captcha at the end of a form instead of throwing an error and not displaying the captcha at all.

Your mileage may vary, but it worked in my use-case.

bsarchive’s picture

#8 seems to be working for me. Thanks.

Liam Morland’s picture

Status: Active » Needs review
Liam Morland’s picture

prabha.venkatesan’s picture

FileSize
15.95 KB

When I apply this patch #8, the error message goes away and I can see only the Captcha element as an anonymous user. The form gives a warning " Unable to display this webform. Please contact the site administrator."
This happens when I close and reopen (unpublish and publish) both the webform content as well as the webform in structure.
PFA https://www.drupal.org/files/issues/2020-10-07/unable%20to%20display%20f...

gaele’s picture

#3099456: Argument 2 passed to CaptchaService::insertCaptchaElement() must be of the type array solves the TypeError bug, and is part of 8.x-1.3. It does not display a captcha widget when no buttons are found. Which is fine for my use case, but unlike the one described in #8, so I'm leaving this issue open.

dancbatista’s picture

Assigned: Unassigned » dancbatista

I will work on it!

dancbatista’s picture

Assigned: dancbatista » Unassigned

In my case, I had the same results as described in #13.

Anybody’s picture

The idea and patch in #8 looks good to me, could anyone write down clear steps to reproduce this in a fresh Drupal environment?
Alternatively or additionally, I think we'd need a test

Grevil’s picture

Version: 8.x-1.x-dev » 2.x-dev
Anybody’s picture

Assigned: Unassigned » Grevil

Thanks @Spokje, I just added the code from your patch in #8 as MR. And it looks correct and useful to me to have this final fallback.

Please review. Afterwards I think this topic can be closed finally. The fallback should fix the last edge-case.

Anybody’s picture

Grevil’s picture

I don't like the patch. We should get clear steps for replicating this behaviour, so we can find a better solution.

Currently, the method will look for an "actions" button group, if there is one, we set the captcha right before it. If there is no "actions" button group, we look for a button, and place it before the first button we find, if there is also no button, we set $placement to NULL and return it.

With the patch, we add a final check for handling $placement being NULL, and place the captcha before the actions button group. But the way this is written, we also add the button, even if no "actions" button group exist AND we add duplicate code.

Anybody’s picture

Well I think the situation isn't good yet, that's correct, but the patch doesn't make things worse from my perspective, it just adds a fallback to prevent errors.

As a follow-up #2698795: Better placement strategy should be seen, but sooner or later the module will need a general refactoring.

So I'm okay with both decisions, adding the proposed code as fallback or do nothing / wait for further progress here (which might never happen). You decide @Grevil, please set the status accordingly.

Grevil’s picture

I removed the changes, added another NULL check and changed the "insertCaptchaElement" attribute definition, so we can be 100% sure, that $placement is only NULL, when we set it NULL. I don't think further checks are needed, as the rest is handled inside insertCaptchaElement() (legacy name: _captcha_insert_captcha_element()), as it also handles cases where key, weight and path of the $placement variable is NULL, this also applies if the whole $placement variable is NULL! So this will probably fix all issues.

Anybody’s picture

Title: Error calling _captcha_insert_captcha_element » [2.x only] Error calling _captcha_insert_captcha_element

Due to the used functionality (parameter typing) this is a 2.x (PHP 8) only change!

Anybody’s picture

Status: Needs review » Reviewed & tested by the community
Grevil’s picture

Status: Reviewed & tested by the community » Fixed

All tests are green! commiting this!

  • Grevil committed 7b79037 on 2.x authored by Anybody
    Issue #3075256: Error calling _captcha_insert_captcha_element
    

Status: Fixed » Closed (fixed)

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