phalcon/cphalcon · error · Phalcon\Filter\Validation\Exceptions\InvalidValidator
One of the validators is not valid
Error message
One of the validators is not valid
What it means
During validate(), every registered validator entry must be an object implementing ValidatorInterface (add() enforces this via its type signature, but setValidators(array) does not check inner entries). InvalidValidator is thrown when a per-field validator entry is not an object — typically a class-name string injected through setValidators() or a subclass.
Source
Thrown at phalcon/Filter/Validation.zep:672
// if user provided entity, bind and assign the data to the entity
this->bind(entity, inputData, whitelist);
}
/**
* Validation classes can implement the 'beforeValidation' callback
*/
if method_exists(this, "beforeValidation") {
let status = this->{"beforeValidation"}(inputData, this->entity, this->messages);
if status === false {
return status;
}
}
for field, validators in validatorData {
for validator in validators {
if unlikely typeof validator != "object" {
throw new InvalidValidator();
}
/**
* Call internal validations, if it returns true, then skip the
* current validator
*/
if this->preChecking(field, validator) {
continue;
}
/**
* Check if the validation must be canceled if this validator fails
*/
if validator->validate(this, field) === false {
if validator->getOption("cancelOnFail") {
break;
}
}View on GitHub (pinned to b7419de9cd)
Solutions
- Instantiate each validator: $validation->setValidators(['email' => [new Email()]])
- Or use the fluent API: $validation->add('email', new Email()) — the <ValidatorInterface> parameter catches this at call time
- For config-driven rules, resolve names through ValidatorFactory: (new ValidatorFactory())->newInstance('email')
Example fix
// before
$validation->setValidators([
'email' => ['\Phalcon\Filter\Validation\Validator\Email'], // string -> throws
]);
// after
$validation->setValidators([
'email' => [new \Phalcon\Filter\Validation\Validator\Email()],
]); Defensive patterns
Strategy: type-guard
Validate before calling
foreach ($validation->getValidators() as $field => $validators) {
foreach ($validators as $v) {
if (!is_object($v)) {
throw new RuntimeException(sprintf('Validator for %s is %s, expected ValidatorInterface object', $field, get_debug_type($v)));
}
}
}
$validation->validate($data); Type guard
function validatorsAreObjects(\Phalcon\Filter\Validation $validation): bool
{
foreach ($validation->getValidators() as $list) {
foreach ($list as $validator) {
if (!$validator instanceof \Phalcon\Filter\Validation\ValidatorInterface) {
return false;
}
}
}
return true;
} Try / catch
use Phalcon\Filter\Validation\Exceptions\InvalidValidator;
try {
$messages = $v->validate($data);
} catch (InvalidValidator $e) {
throw new RuntimeException('Validator map contains non-objects; instantiate validators or use add()', 0, $e);
} Prevention
- Build rule sets with add()/rule() so the ValidatorInterface type is enforced at registration time
- Map config strings through ValidatorFactory::newInstance() before injecting
- Never inject class-name strings via setValidators()
When it happens
Trigger: $validation->setValidators(['email' => ['Phalcon\Filter\Validation\Validator\Email']]) — string class names instead of instances; a subclass building $validators with ['field' => 'SomeValidatorClass']; a config-driven builder mapping YAML validator names straight into the map.
Common situations: Defining validators declaratively in config (strings) without instantiating them through Phalcon\Filter\Validation\ValidatorFactory; copying older examples that predates the typed add() signature; caching serialized maps that lost the objects.
Related errors
- Field must be passed as array of fields or string
- Entity must be an object
- Invalid data to validate
- Arguments must be an array or string, {type} given
- Invalid data type for merge.
AI-assisted analysis of phalcon/cphalcon@b7419de9cd (2026-08-21).
Data as JSON: /api/errors/a10a816abd6afc08.
Report an issue: GitHub.