phalcon/cphalcon · error · Phalcon\Container\Exceptions\FrozenDefinition

Cannot modify frozen definition '{name}'

Error message

Cannot modify frozen definition '{name}'

What it means

A ServiceDefinition freezes the first time the container resolves it: resolve() calls definition->freeze() before building, and checkFrozen() thereafter blocks every mutation (setClass, setFactory, setExtenders, setConstructorArgs, ...). FrozenDefinition means you tried to reconfigure a service that was already instantiated.

Source

Thrown at phalcon/Container/Definition/ServiceDefinition.zep:542

     */
    public function unsetFactory() -> <static>
    {
        this->checkFrozen();
        let this->factory = null;

        return this;
    }

    /**
     * Check if frozen
     *
     * @return void
     * @throws FrozenDefinition
     */
    protected function checkFrozen() -> void
    {
        if (this->frozen) {
            throw new FrozenDefinition(this->serviceName);
        }
    }

    /**
     * Resolve arguments
     *
     * @param object $container
     * @param array  $args
     *
     * @return array
     */
    private function resolveArgs(object container, array args) -> array
    {
        var resolved, key, argument;

        let resolved = [];

        for key, argument in args {

View on GitHub (pinned to b7419de9cd)

Solutions

  1. Re-register instead of mutating: $container->set('db', NewConnection::class) installs a fresh, unfrozen definition
  2. Configure definitions fully before the first get() — ideally inside provider registration
  3. Build a new container (via ContainerFactory) when a clean state is needed, the usual fix in tests
  4. Order bootstrap so all overrides run before the first resolution of the affected service

Example fix

// before
$container->get('db');
$container->getDefinition('db')->setClass(OtherConnection::class); // FrozenDefinition

// after
$container->get('db');
$container->set('db', OtherConnection::class);
Defensive patterns

Strategy: validation

Validate before calling

// Mutate only definitions that have not been resolved yet
if (!$container->hasInstance('db')) {
    $container->getDefinition('db')->setClass(OtherConnection::class);
} else {
    $container->set('db', OtherConnection::class); // replace instead of mutate
}

Try / catch

use Phalcon\Container\Exceptions\FrozenDefinition;

try {
    $container->getDefinition('db')->setFactory($fn);
} catch (FrozenDefinition $e) {
    $container->set('db', $fn); // re-register a fresh definition instead
}

Prevention

When it happens

Trigger: $container->get('db'); followed by $container->getDefinition('db')->setClass(OtherConnection::class); tests mutating definitions between cases without a fresh container; runtime overrides in code that runs after something else already resolved the singleton.

Common situations: Test suites reusing one container across cases; plugins overriding services after boot resolution; long-running workers (Swoole, queues) where an early request already called get().

Related errors


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