egulias/EmailValidator · error · EmptyValidationList

Empty validation list is not allowed

Error message

Empty validation list is not allowed

What it means

MultipleValidationWithAnd is a composite validator that runs a list of EmailValidation instances and returns true only if all of them pass (errors are collected into MultipleErrors). Its constructor immediately throws EmptyValidationList (an InvalidArgumentException subclass) when the $validations array is empty, because a composite with zero validators is meaningless: isValid() would trivially return true for every address, silently accepting invalid email. The library fails fast at construction time instead of producing a misleading always-valid validator.

Source

Thrown at src/Validation/MultipleValidationWithAnd.php:42

    /**
     * @var Warning[]
     */
    private $warnings = [];

    /**
     * @var MultipleErrors|null
     */
    private $error;

    /**
     * @param EmailValidation[] $validations The validations.
     * @param int               $mode        The validation mode (one of the constants).
     */
    public function __construct(private readonly array $validations, private readonly int $mode = self::ALLOW_ALL_ERRORS)
    {
        if (count($validations) == 0) {
            throw new EmptyValidationList();
        }
    }

    /**
     * {@inheritdoc}
     */
    public function isValid(string $email, EmailLexer $emailLexer): bool
    {
        $result = true;
        foreach ($this->validations as $validation) {
            $emailLexer->reset();
            $validationResult = $validation->isValid($email, $emailLexer);
            $result = $result && $validationResult;
            $this->warnings = [...$this->warnings, ...$validation->getWarnings()];
            if (!$validationResult) {
                $this->processError($validation);
            }

View on GitHub (pinned to d42c8731f0)

Solutions

  1. Pass at least one real validation, e.g. `new MultipleValidationWithAnd([new RFCValidation()])` — if you conditionally build the list, fall back to a sensible default such as RFCValidation when the list ends up empty.
  2. If the list comes from configuration, validate it earlier: throw your own clear configuration exception (e.g. 'email.validations must list at least one rule') before reaching this constructor, so the failure names your config key instead of a library class.
  3. Guard with an explicit check and skip email validation only if an empty rule set legitimately means 'no validation' in your domain — otherwise never silently skip, since that reintroduces the accept-everything behavior the exception prevents.

Example fix

// before
$validations = array_filter([
    $useRfc ? new RFCValidation() : null,
    $useDns ? new DNSCheckValidation() : null,
]);
$validator = new MultipleValidationWithAnd($validations); // throws EmptyValidationList when both flags are false

// after
$validations = array_filter([
    $useRfc ? new RFCValidation() : null,
    $useDns ? new DNSCheckValidation() : null,
]);
if ($validations === []) {
    $validations = [new RFCValidation()];
}
$validator = new MultipleValidationWithAnd($validations);
Defensive patterns

Strategy: validation

Validate before calling

$validations = array_filter([
    $strict ? new NoRFCWarningsValidation() : null,
    $checkDns ? new DNSCheckValidation() : null,
]);
if (count($validations) === 0) {
    throw new \InvalidArgumentException('At least one email validation rule must be configured.');
}
return new MultipleValidationWithAnd(array_values($validations));

Type guard

/** @param list<\Egulias\EmailValidator\Validation\EmailValidation> $validations */
function isNonEmptyValidationList(array $validations): bool
{
    return $validations !== []
        && array_all($validations, static fn ($v) => $v instanceof \Egulias\EmailValidator\Validation\EmailValidation);
}

Try / catch

try {
    $multiple = new MultipleValidationWithAnd($list);
} catch (\Egulias\EmailValidator\Validation\Exception\EmptyValidationList $e) {
    // configuration bug: log it and fall back to a default validator, never to 'no validation'
    $multiple = new MultipleValidationWithAnd([new RFCValidation()]);
}

Prevention

When it happens

Trigger: Constructing `new MultipleValidationWithAnd([])` with a literal empty array. More often, passing a dynamically built list that turned out empty, e.g. `$validations = array_filter([ $x ? new RFCValidation() : null, $y ? new DNSCheckValidation() : null ]); new MultipleValidationWithAnd($validations);` when every condition was false. Also hit when a config array of validation FQCNs is empty or a refactoring removes the last entry from a hardcoded list.

Common situations: Enabling/disabling validations via config flags (yaml/env) where all flags default to off; building the list with array_filter/array_map that can yield []; wrapping the validator behind a factory that receives an empty 'validators' option; upgrading a codebase where a validation list was left as a placeholder [].

Related errors


AI-assisted analysis of egulias/EmailValidator@d42c8731f0 (2026-08-21). Data as JSON: /api/errors/8f73bc8d011c138e. Report an issue: GitHub.