phalcon/cphalcon · error · Phalcon\Filter\Validation\Exceptions\InvalidFilterService
Returned 'filter' service is invalid
Error message
Returned 'filter' service is invalid
What it means
After obtaining a container, bind() resolves container->getShared('filter') and expects an object implementing FilterInterface. InvalidFilterService is thrown when the service resolves but is not an object — typically a misconfigured DI definition that returns a string (a class name), array, or scalar instead of a filter instance.
Source
Thrown at phalcon/Filter/Validation.zep:208
let this->data = data;
this->setEntity(entity);
// if data is not an array / object, entity is null, or data is empty, then no need to proceed further
if unlikely (typeof data != "array" && typeof data != "object") || (null === entity) || empty data {
return this;
}
let container = this->getDI();
if container === null {
let container = Di::getDefault();
if container === null {
throw new FilterServiceUnavailable();
}
}
let filterService = <FilterInterface> container->getShared("filter");
if unlikely typeof filterService != "object" {
throw new InvalidFilterService();
}
if empty whitelist {
let whitelist = this->whitelist;
}
let filters = this->filters;
for field, value in data {
/**
* Skip numeric (integer) keys; entity setters and properties are
* always string-named, so camelize() would fail on them. See
* cphalcon issue #17173.
*/
if typeof field != "string" {
continue;
}
View on GitHub (pinned to b7419de9cd)
Solutions
- Fix the service to return an instance: 'filter' => function () { return (new FilterFactory())->newInstance(); }
- Return your custom Filter object implementing Phalcon\Filter\FilterInterface
- Verify after building the container: assert($di->getShared('filter') instanceof FilterInterface)
Example fix
// before
$di->setShared('filter', function () {
return \Phalcon\Filter\FilterFactory::class; // string, not an object
});
// after
$di->setShared('filter', function () {
return (new \Phalcon\Filter\FilterFactory())->newInstance();
}); Defensive patterns
Strategy: type-guard
Validate before calling
$filter = $di->getShared('filter');
if (!is_object($filter)) {
throw new RuntimeException('DI filter service must return an object, got ' . get_debug_type($filter));
} Type guard
function assertFilterService($service): \Phalcon\Filter\FilterInterface
{
if (!$service instanceof \Phalcon\Filter\FilterInterface) {
throw new RuntimeException('filter service misconfigured: ' . get_debug_type($service));
}
return $service;
} Try / catch
use Phalcon\Filter\Validation\Exceptions\InvalidFilterService;
try {
$v->bind($entity, $data);
} catch (InvalidFilterService $e) {
throw new RuntimeException('Fix DI: filter must resolve to FilterInterface instance', 0, $e);
} Prevention
- Register the filter service as a closure that returns (new FilterFactory())->newInstance()
- Add a container smoke test: getShared('filter') instanceof FilterInterface after bootstrap
When it happens
Trigger: A DI closure registered as 'filter' => fn () => FilterFactory::class returning the class name string; a shared service overwritten elsewhere with a non-object; definitions imported from config that map 'filter' to a string class without instantiation.
Common situations: Hand-written DI closures that forget ->newInstance(); copying the 'filter' registration from docs but dropping the parentheses; overriding the service in an environment-specific config file with a plain class name.
Related errors
- A dependency injection container is required to access the '
- A dependency injection container is required to access the '
- Unable to insert into {table} without data
- The number of values in the update is not the same as fields
- RETURNING requires at least one column or '*'
AI-assisted analysis of phalcon/cphalcon@b7419de9cd (2026-08-21).
Data as JSON: /api/errors/c728bdf8498dba76.
Report an issue: GitHub.