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

Service '{name}' not registered

Error message

Service '{name}' not registered

What it means

getService() calls get() and then enforces that the resolved value is a PHP object; ServiceNotRegistered is thrown when the name resolves fine but to a scalar, array, or null. With this container's processors, the usual source is a closure definition whose factory returns a non-object.

Source

Thrown at phalcon/Container/Container.zep:318

    }

    /**
     * Resolve an return a service
     *
     * @param string $serviceName
     *
     * @return object
     * @throws ServiceNotFound
     * @throws ServiceNotRegistered
     */
    public function getService(string serviceName) -> object
    {
        var result;

        let result = this->get(serviceName);

        if (!is_object(result)) {
            throw new ServiceNotRegistered(serviceName);
        }

        return result;
    }

    /**
     * Returns the names of every registered service definition. Names that
     * only exist as an alias, a pre-set instance or a parameter are not
     * included.
     *
     * @return array<int, string>
     */
    public function getServiceNames() -> array
    {
        return array_keys(this->services);
    }

    /**

View on GitHub (pinned to b7419de9cd)

Solutions

  1. Store non-object values as parameters: setParameter('settings', [...]) and read with getParameter()
  2. Make the factory return an object (e.g. a Config/DTO object) if consumers genuinely need a service
  3. Use get() instead of getService() when a non-object result is legitimate for that name
  4. Guard manually: $result = $container->get('settings'); if (!is_object($result)) { /* parameter path */ }

Example fix

// before
$container->set('settings', fn () => ['debug' => true]);
$settings = $container->getService('settings'); // ServiceNotRegistered

// after
$container->setParameter('settings', ['debug' => true]);
$settings = $container->getParameter('settings');
Defensive patterns

Strategy: type-guard

Validate before calling

$result = $container->get('settings');
if (!is_object($result)) {
    // non-object entry: treat as value/parameter, do not call getService()
    throw new LogicException("'settings' does not resolve to an object.");
}

Type guard

function resolvesToObject(\Phalcon\Container\Container $container, string $name): bool
{
    return is_object($container->get($name));
}

Try / catch

use Phalcon\Container\Exceptions\ServiceNotRegistered;

try {
    $svc = $container->getService('settings');
} catch (ServiceNotRegistered $e) {
    // entry is a value, not a service object; fall back to get()/getParameter()
}

Prevention

When it happens

Trigger: $container->set('settings', fn () => ['debug' => true]); then $container->getService('settings') — the closure returns an array; likewise a closure returning a string, int, or null.

Common situations: Storing configuration arrays or primitives as container entries (set() allows any closure return) and later handing them to code that requires a service object; generic code paths that assume every container entry is an object.

Related errors


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