Problem/Motivation
Hope this hasn't been addressed elsewhere before, I've looked for a lot but could find any reference.
Here is the exception we get on a range of websites occasionally:
TypeError: Argument 1 passed to Egulias\EmailValidator\EmailValidator::isValid() must be of the type string, null given
0 /var/www/html/web/core/lib/Drupal/Component/Utility/EmailValidator.php(30): Egulias\\\\EmailValidator\\\\EmailValidator->isValid()\", \
1 /var/www/html/web/core/modules/user/src/Form/UserPasswordForm.php(178): Drupal\\\\Component\\\\Utility\\\\EmailValidator->isValid()\", \
2 [internal function]: Drupal\\\\user\\\\Form\\\\UserPasswordForm->validateForm()\", \
3 /var/www/html/web/core/lib/Drupal/Core/Form/FormValidator.php(82): call_user_func_array()\", \
4 /var/www/html/web/core/lib/Drupal/Core/Form/FormValidator.php(275): Drupal\\\\Core\\\\Form\\\\FormValidator->executeValidateHandlers()\", \
5 /var/www/html/web/core/lib/Drupal/Core/Form/FormValidator.php(118): Drupal\\\\Core\\\\Form\\\\FormValidator->doValidateForm()\", \
6 /var/www/html/web/core/lib/Drupal/Core/Form/FormBuilder.php(588): Drupal\\\\Core\\\\Form\\\\FormValidator->validateForm()\", \
7 /var/www/html/web/core/lib/Drupal/Core/Form/FormBuilder.php(320): Drupal\\\\Core\\\\Form\\\\FormBuilder->processForm()\", \
8 /var/www/html/web/core/lib/Drupal/Core/Controller/FormController.php(73): Drupal\\\\Core\\\\Form\\\\FormBuilder->buildForm()\", \
9 [internal function]: Drupal\\\\Core\\\\Controller\\\\FormController->getContentResult()\", \
10 /var/www/html/web/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php(123): call_user_func_array()\", \
11 /var/www/html/web/core/lib/Drupal/Core/Render/Renderer.php(564): Drupal\\\\Core\\\\EventSubscriber\\\\EarlyRenderingControllerWrapperSubscriber->Drupal\\\\Core\\\\EventSubscriber\\\\{closure}()\", \
12 /var/www/html/web/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php(124): Drupal\\\\Core\\\\Render\\\\Renderer->executeInRenderContext()\", \
13 /var/www/html/web/core/lib/Drupal/Core/EventSubscriber/EarlyRenderingControllerWrapperSubscriber.php(97): Drupal\\\\Core\\\\EventSubscriber\\\\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext()\", \
14 /var/www/html/vendor/symfony/http-kernel/HttpKernel.php(159): Drupal\\\\Core\\\\EventSubscriber\\\\EarlyRenderingControllerWrapperSubscriber->Drupal\\\\Core\\\\EventSubscriber\\\\{closure}()\", \
15 /var/www/html/vendor/symfony/http-kernel/HttpKernel.php(81): Symfony\\\\Component\\\\HttpKernel\\\\HttpKernel->handleRaw()\", \
16 /var/www/html/web/core/lib/Drupal/Core/StackMiddleware/Session.php(58): Symfony\\\\Component\\\\HttpKernel\\\\HttpKernel->handle()\", \
17 /var/www/html/web/core/lib/Drupal/Core/StackMiddleware/KernelPreHandle.php(48): Drupal\\\\Core\\\\StackMiddleware\\\\Session->handle()\", \
18 /var/www/html/web/core/modules/page_cache/src/StackMiddleware/PageCache.php(106): Drupal\\\\Core\\\\StackMiddleware\\\\KernelPreHandle->handle()\", \
19 /var/www/html/web/core/modules/page_cache/src/StackMiddleware/PageCache.php(85): Drupal\\\\page_cache\\\\StackMiddleware\\\\PageCache->pass()\", \
20 /var/www/html/web/core/lib/Drupal/Core/StackMiddleware/ReverseProxyMiddleware.php(48): Drupal\\\\page_cache\\\\StackMiddleware\\\\PageCache->handle()\", \
21 /var/www/html/web/core/lib/Drupal/Core/StackMiddleware/NegotiationMiddleware.php(51): Drupal\\\\Core\\\\StackMiddleware\\\\ReverseProxyMiddleware->handle()\", \
22 /var/www/html/vendor/stack/builder/src/Stack/StackedHttpKernel.php(23): Drupal\\\\Core\\\\StackMiddleware\\\\NegotiationMiddleware->handle()\", \
23 /var/www/html/web/core/lib/Drupal/Core/DrupalKernel.php(709): Stack\\\\StackedHttpKernel->handle()\", \
24 /var/www/html/web/index.php(19): Drupal\\\\Core\\\\DrupalKernel->handle()\", \
25 {main}\"]}"
The method Egulias\EmailValidator\EmailValidator::isValid()
explicitly declares the email to be a string, but it receives a NULL.
Well, it would be easy to prevent that from happening. However, what makes me wonder is how that could ever happen because the email is a required field and if the request gets through the Symfony stack, the form build and validation to then get to the email validation, I would bet that the submission did not contain an empty email. And even if, that wouldn't turn into a NULL, that would then be an empty string.
Therefore, the relevant question might be, what a user can enter into the password reset form that results in this exception. The code in core looks like this:
// First, see if the input is possibly valid as a username.
$name = trim($form_state->getValue('name'));
$definition = BaseFieldDefinition::create('string')
->addConstraint('UserName', []);
$data = $this->typedDataManager->create($definition);
$data->setValue($name);
$violations = $data->validate();
// Usernames have a maximum length shorter than email addresses. Only print
// this error if the input is not valid as a username or email address.
if ($violations->count() > 0 && !$this->emailValidator->isValid($name)) {
$form_state->setErrorByName('name', $this->t("The username or email address is invalid."));
return;
}
Honestly, I have no idea how $name can ever be NULL. I also looked around for contrib modules who might have an impact here, but none seems to be the culprit.
The last idea I'm having, somebody tries some tricky POST requests on https://www.example.com/user/password with some data which would result in this. Otherwise I'm running out of ideas.