{"record":{"id":"4228e6b9006ad379","repo":"phalcon/cphalcon","slug":"cannot-extend-already-resolved-service-name","errorCode":null,"errorMessage":"Cannot extend already-resolved service '{name}'","messagePattern":"Cannot extend already-resolved service '(.+?)'","errorType":"exception","errorClass":"Phalcon\\Container\\Exceptions\\CannotExtendResolved","httpStatus":null,"severity":"error","filePath":"phalcon/Container/Container.zep","lineNumber":166,"sourceCode":"        };\n    }\n\n    /**\n     * Extends the definition\n     *\n     * @param string   $name\n     * @param callable $callable\n     *\n     * @return void\n     * @throws CannotExtendResolved\n     * @throws ServiceNotFound\n     */\n    public function extend(string name, callable callableObject) -> void\n    {\n        let name = this->resolveAlias(name);\n\n        if (array_key_exists(name, this->instances)) {\n            throw new CannotExtendResolved(name);\n        }\n\n        if (!array_key_exists(name, this->services)) {\n            throw new ServiceNotFound(name);\n        }\n\n        this->services[name]->addExtender(callableObject);\n    }\n\n    /**\n     * Resolve and return an element registerd in the container\n     *\n     * @param string $name\n     *\n     * @return mixed\n     * @throws ServiceNotFound\n     */\n    public function get(string name) -> mixed","sourceCodeStart":148,"sourceCodeEnd":184,"githubUrl":"https://github.com/phalcon/cphalcon/blob/b7419de9cd0a8a3f48441ead84c9f8415d463e25/phalcon/Container/Container.zep#L148-L184","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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()"],"exampleFix":"// before\n$container->get('logger');          // resolves the service\n$container->extend('logger', $fn);   // CannotExtendResolved\n\n// after\n$container->extend('logger', $fn);   // extend first, at registration time\n$logger = $container->get('logger'); // resolution applies the extender","handlingStrategy":"try-catch","validationCode":"// Cheap guard: extend only during registration, before anything resolves the service\n// Container exposes no public \"wasResolved\" check, so structure boot order instead:\n$container->set('logger', $loggerDefinition);\n$container->extend('logger', $fn);   // immediately after set(), still unresolved","typeGuard":null,"tryCatchPattern":"use \\Phalcon\\Container\\Exception\\CannotExtendResolved;\n\ntry {\n    $container->extend('logger', $fn);\n} catch (CannotExtendResolved $e) {\n    // Service already instantiated: redefine instead of extending.\n    // Resolve, decorate, and replace the instance so all future get() calls see it.\n    $decorated = $fn($container->get('logger'), $container);\n    $container->set('logger', $decorated);\n}","preventionTips":["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"],"tags":["phalcon","container","di","service","extend"],"backgroundTag":"service-already-resolved","analyzedSha":"b7419de9cd0a8a3f48441ead84c9f8415d463e25","analyzedAt":"2026-08-21T06:21:18.811Z","schemaVersion":2},"datasetVersion":"2026-08-21T11:28:35.574Z"}