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) -> mixed

View on GitHub (pinned to b7419de9cd)

Solutions

  1. Register extenders during boot, before any resolution — right after set() in your service provider
  2. If the service is already resolved, redefine it with set() instead of extend(), or resolve, decorate, and re-set the instance yourself
  3. 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

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


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