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
- Re-register instead of mutating: $container->set('db', NewConnection::class) installs a fresh, unfrozen definition
- Configure definitions fully before the first get() — ideally inside provider registration
- Build a new container (via ContainerFactory) when a clean state is needed, the usual fix in tests
- 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
- Finish all definition configuration before the first get(); treat post-resolution edits as bugs
- In tests, build a fresh container per case instead of reconfiguring a shared one
- Prefer set() to replace a definition rather than mutating an existing one at runtime
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
- Service '{name}' not found
- Instance '{name}' not found
- Parameter '{name}' not found
- Service '{name}' not registered
- Circular alias detected: '{alias}'
AI-assisted analysis of phalcon/cphalcon@b7419de9cd (2026-08-21).
Data as JSON: /api/errors/97f42029636bea0f.
Report an issue: GitHub.