phalcon/cphalcon · error · Phalcon\Filter\Validation\Exceptions\FilterServiceUnavailable

A dependency injection container is required to access the '

Error message

A dependency injection container is required to access the 'filter' service

What it means

Validation::bind() pre-sanitizes incoming data through the DI 'filter' service, so it needs a service container. FilterServiceUnavailable is thrown when the validation object has no container injected (getDI() is null) and the global default container Di::getDefault() is also null — i.e., the validation runs standalone with no DI anywhere.

Source

Thrown at phalcon/Filter/Validation.zep:203

     */
    public function bind(var entity, var data, array whitelist = []) -> <static>
    {
        var container, field, value, fieldFilters, filterService, filters, method;

        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.

View on GitHub (pinned to b7419de9cd)

Solutions

  1. Set a container on the validation: $validation->setDI(new FactoryDefault()) (or your existing $di)
  2. Or establish the global default once at bootstrap: Di::setDefault($di)
  3. Ensure the container actually defines a 'filter' service once the container issue is fixed (next error will be FilterServiceUnavailable/InvalidFilterService otherwise)

Example fix

// before
$v = new Validation();
$v->bind($entity, $_POST); // throws FilterServiceUnavailable: no DI anywhere

// after
$di = new FactoryDefault();
Di::setDefault($di);
$v = new Validation();
$v->setDI($di);
$v->bind($entity, $_POST);
Defensive patterns

Strategy: validation

Validate before calling

if ($validation->getDI() === null && Di::getDefault() === null) {
    throw new RuntimeException('Validation needs a DI container with a filter service; call setDI() or Di::setDefault()');
}
$validation->bind($entity, $data);

Type guard

function hasFilterContainer(\Phalcon\Filter\Validation $v): bool
{
    return $v->getDI() !== null || \Phalcon\Di\Di::getDefault() !== null;
}

Try / catch

use Phalcon\Filter\Validation\Exceptions\FilterServiceUnavailable;
try {
    $v->bind($entity, $data);
} catch (FilterServiceUnavailable $e) {
    $v->setDI(new FactoryDefault()); // bootstrap on demand in workers/CLI
    $v->bind($entity, $data);
}

Prevention

When it happens

Trigger: $v = new Validation(); $v->bind($entity, $data); in a plain PHP script, unit test, or queue worker where no FactoryDefault was ever created; calling bind() before Di::setDefault() runs; Di::reset() in a test tearDown leaving the default container null while a later bind() still executes.

Common situations: Using Phalcon\Filter\Validation outside a full Phalcon application (micro-service, CLI script, PHPUnit); long-running workers started before the DI was bootstrapped; tests that reset DI state between cases.

Related errors


AI-assisted analysis of phalcon/cphalcon@b7419de9cd (2026-08-21). Data as JSON: /api/errors/ac2a6e350c0ba244. Report an issue: GitHub.