phalcon/cphalcon · error · Phalcon\Mvc\Router\Exceptions\AnnotationsServiceUnavailable
A dependency injection container is required to access the '
Error message
A dependency injection container is required to access the 'annotations' service
What it means
The Annotations router reads controller/method annotations through the shared 'annotations' service, which it resolves from the dependency injection container. AnnotationsRouter::handle() first asserts that a DI container is present; with no container attached (or a non-object container) it throws AnnotationsServiceUnavailable before any controller scanning begins.
Source
Thrown at phalcon/Mvc/Router/Annotations.zep:114
return this->handlers;
}
/**
* Produce the routing parameters from the rewrite information
*/
public function handle( string uri) -> void
{
var annotationsService, handlers, controllerSuffix, scope, prefix,
route, compiledPattern, container, handler, controllerName,
lowerControllerName, namespaceName, moduleName, handlerAnnotations,
classAnnotations, annotations, annotation, methodAnnotations, method,
collection;
string sufixed;
let container = <DiInterface> this->container;
if unlikely typeof container != "object" {
throw new AnnotationsServiceUnavailable();
}
let handlers = this->handlers;
let controllerSuffix = this->controllerSuffix;
let annotationsService = container->getShared("annotations");
for scope in handlers {
if typeof scope != "array" {
continue;
}
/**
* A prefix (if any) must be in position 0
*/
let prefix = scope[0];
if !empty prefix {
/**View on GitHub (pinned to b7419de9cd)
Solutions
- Attach a container: $router = new Router\Annotations(); $router->setDI(new \Phalcon\Di\FactoryDefault()); then add handlers and call handle()
- In full applications, reuse the existing DI: $router->setDI($application->getDI()) or via Di::getDefault()
- If using a hand-built Di, ensure it can resolve 'annotations' (register Annotations\Adapter) — the container check passes, but the service must exist
Example fix
// before
$router = new \Phalcon\Mvc\Router\Annotations(false);
$router->addResource('App\Controllers\Posts');
$router->handle('/posts'); // no DI container set
// after
$di = new \Phalcon\Di\FactoryDefault();
$router = new \Phalcon\Mvc\Router\Annotations(false);
$router->setDI($di);
$router->addResource('App\Controllers\Posts');
$router->handle('/posts'); Defensive patterns
Strategy: type-guard
Validate before calling
// ensure a container exists before the Annotations router handles anything
$di = \Phalcon\Di\Di::getDefault();
if ($di === null) {
$di = new \Phalcon\Di\FactoryDefault();
\Phalcon\Di\Di::setDefault($di);
}
$router->setDI($di);
$router->handle($uri); Type guard
function hasContainer(\Phalcon\Mvc\RouterInterface $router): bool
{
$di = method_exists($router, 'getDI') ? $router->getDI() : null;
return $di instanceof \Phalcon\Di\DiInterface;
} Try / catch
try {
$router->handle($uri);
} catch (\Phalcon\Mvc\Router\Exceptions\AnnotationsServiceUnavailable $e) {
$logger->error('Annotations router used without DI container');
throw new RuntimeException('Router bootstrap incomplete: attach a DI container', 0, $e);
} Prevention
- Always call $router->setDI($di) right after constructing an Annotations router, in app code and tests alike
- Register or verify the 'annotations' service in custom containers before first handle()
- In unit tests, inject a container with a stub annotations adapter to avoid full bootstrapping
When it happens
Trigger: Creating `new Router\Annotations()` in a unit test or standalone script and calling handle('/uri') without setDI(); a micro-app that never booted FactoryDefault; the container was set on a different router instance or reset to null.
Common situations: PHPUnit tests constructing the router directly; CLI scripts reusing router classes outside the MVC stack; refactoring bootstrap so the router is built before the DI container exists.
Related errors
- The 'callback' parameter must be either a callable or NULL.
- A dependency injection container is required to access the '
- Invalid module definition for module '{moduleName}': The mod
- Arguments must be an array or string, {type} given
- Before-Match callback is not callable in matched route '{pat
AI-assisted analysis of phalcon/cphalcon@b7419de9cd (2026-08-21).
Data as JSON: /api/errors/695c2097803e18f7.
Report an issue: GitHub.