phalcon/cphalcon · error · Phalcon\Container\Exceptions\CannotExtendResolved
Cannot extend already-resolved service '{name}'
Error message
Cannot extend already-resolved service '{name}' What it means
Container::extend() attaches an extender callable to a registered service's definition, which is only meaningful before the service is first resolved. Once get()/shared resolution has placed an instance in the container's instances map, extending is refused with CannotExtendResolved — mutating an already-live instance would change behavior for existing holders.
Source
Thrown at phalcon/Container/Container.zep:166
};
}
/**
* Extends the definition
*
* @param string $name
* @param callable $callable
*
* @return void
* @throws CannotExtendResolved
* @throws ServiceNotFound
*/
public function extend(string name, callable callableObject) -> void
{
let name = this->resolveAlias(name);
if (array_key_exists(name, this->instances)) {
throw new CannotExtendResolved(name);
}
if (!array_key_exists(name, this->services)) {
throw new ServiceNotFound(name);
}
this->services[name]->addExtender(callableObject);
}
/**
* Resolve and return an element registerd in the container
*
* @param string $name
*
* @return mixed
* @throws ServiceNotFound
*/
public function get(string name) -> mixedView on GitHub (pinned to b7419de9cd)
Solutions
- Register extenders during boot, before any resolution — right after set() in your service provider
- If the service is already resolved, redefine it with set() instead of extend(), or resolve, decorate, and re-set the instance yourself
- In plugins, check whether the service is already up and use a decorator/new service name instead of extend()
Example fix
// before
$container->get('logger'); // resolves the service
$container->extend('logger', $fn); // CannotExtendResolved
// after
$container->extend('logger', $fn); // extend first, at registration time
$logger = $container->get('logger'); // resolution applies the extender Defensive patterns
Strategy: try-catch
Validate before calling
// Cheap guard: extend only during registration, before anything resolves the service
// Container exposes no public "wasResolved" check, so structure boot order instead:
$container->set('logger', $loggerDefinition);
$container->extend('logger', $fn); // immediately after set(), still unresolved Try / catch
use \Phalcon\Container\Exception\CannotExtendResolved;
try {
$container->extend('logger', $fn);
} catch (CannotExtendResolved $e) {
// Service already instantiated: redefine instead of extending.
// Resolve, decorate, and replace the instance so all future get() calls see it.
$decorated = $fn($container->get('logger'), $container);
$container->set('logger', $decorated);
} Prevention
- Register all extenders at boot, right after set(), before the first get() or injection
- In plugin systems, treat CannotExtendResolved as a signal to redefine (set) or decorate rather than extend
- In tests, build a fresh container per test so earlier resolutions cannot poison extend()
- For long-running workers, never extend resolved singletons between jobs — register a new decorated service name
When it happens
Trigger: Calling $container->extend('logger', $fn) after $container->get('logger') (or after the logger was injected into another service earlier in the request). Also plugin/provider code registering extenders late, after bootstrap already resolved shared services.
Common situations: Runtime plugin systems that extend core services after the application booted; test suites where an earlier test resolved the service on a shared container; long-running workers (queues, Swoole) that try to extend services between jobs.
Related errors
- The parameter must be an instance of Collection or DiInterfa
- Service '{name}' not found
- Argument at position {} must have a type
- Service '{}' is required in parameter on position {}
- Service 'value' is required in parameter on position {}
AI-assisted analysis of phalcon/cphalcon@b7419de9cd (2026-08-21).
Data as JSON: /api/errors/4228e6b9006ad379.
Report an issue: GitHub.