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
- 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.
- 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.
- 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
- Default dynamically built validation lists to at least one rule (e.g. RFCValidation) before constructing the composite.
- Validate validator-config arrays (DI container definitions, yaml/env lists) at boot time so an empty list fails with your own configuration error naming the config key.
- When using array_filter to build the list, remember it can return []; always count() before passing to MultipleValidationWithAnd.
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.