{"record":{"id":"8f73bc8d011c138e","repo":"egulias/EmailValidator","slug":"empty-validation-list-is-not-allowed","errorCode":null,"errorMessage":"Empty validation list is not allowed","messagePattern":"Empty validation list is not allowed","errorType":"exception","errorClass":"EmptyValidationList","httpStatus":null,"severity":"error","filePath":"src/Validation/MultipleValidationWithAnd.php","lineNumber":42,"sourceCode":"\n    /**\n     * @var Warning[]\n     */\n    private $warnings = [];\n\n    /**\n     * @var MultipleErrors|null\n     */\n    private $error;\n\n    /**\n     * @param EmailValidation[] $validations The validations.\n     * @param int               $mode        The validation mode (one of the constants).\n     */\n    public function __construct(private readonly array $validations, private readonly int $mode = self::ALLOW_ALL_ERRORS)\n    {\n        if (count($validations) == 0) {\n            throw new EmptyValidationList();\n        }\n    }\n\n    /**\n     * {@inheritdoc}\n     */\n    public function isValid(string $email, EmailLexer $emailLexer): bool\n    {\n        $result = true;\n        foreach ($this->validations as $validation) {\n            $emailLexer->reset();\n            $validationResult = $validation->isValid($email, $emailLexer);\n            $result = $result && $validationResult;\n            $this->warnings = [...$this->warnings, ...$validation->getWarnings()];\n            if (!$validationResult) {\n                $this->processError($validation);\n            }\n","sourceCodeStart":24,"sourceCodeEnd":60,"githubUrl":"https://github.com/egulias/EmailValidator/blob/d42c8731f0624ad6bdc8d3e5e9a4524f68801cfa/src/Validation/MultipleValidationWithAnd.php#L24-L60","documentation":"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.","triggerScenarios":"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.","commonSituations":"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 [].","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."],"exampleFix":"// before\n$validations = array_filter([\n    $useRfc ? new RFCValidation() : null,\n    $useDns ? new DNSCheckValidation() : null,\n]);\n$validator = new MultipleValidationWithAnd($validations); // throws EmptyValidationList when both flags are false\n\n// after\n$validations = array_filter([\n    $useRfc ? new RFCValidation() : null,\n    $useDns ? new DNSCheckValidation() : null,\n]);\nif ($validations === []) {\n    $validations = [new RFCValidation()];\n}\n$validator = new MultipleValidationWithAnd($validations);","handlingStrategy":"validation","validationCode":"$validations = array_filter([\n    $strict ? new NoRFCWarningsValidation() : null,\n    $checkDns ? new DNSCheckValidation() : null,\n]);\nif (count($validations) === 0) {\n    throw new \\InvalidArgumentException('At least one email validation rule must be configured.');\n}\nreturn new MultipleValidationWithAnd(array_values($validations));","typeGuard":"/** @param list<\\Egulias\\EmailValidator\\Validation\\EmailValidation> $validations */\nfunction isNonEmptyValidationList(array $validations): bool\n{\n    return $validations !== []\n        && array_all($validations, static fn ($v) => $v instanceof \\Egulias\\EmailValidator\\Validation\\EmailValidation);\n}","tryCatchPattern":"try {\n    $multiple = new MultipleValidationWithAnd($list);\n} catch (\\Egulias\\EmailValidator\\Validation\\Exception\\EmptyValidationList $e) {\n    // configuration bug: log it and fall back to a default validator, never to 'no validation'\n    $multiple = new MultipleValidationWithAnd([new RFCValidation()]);\n}","preventionTips":["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."],"tags":["php","email-validator","invalid-argument","constructor","empty-array"],"backgroundTag":"empty-collection-argument","analyzedSha":"d42c8731f0624ad6bdc8d3e5e9a4524f68801cfa","analyzedAt":"2026-08-21T01:55:18.494Z","schemaVersion":2},"datasetVersion":"2026-08-21T03:17:12.404Z"}