{"record":{"id":"5a308e66d0850acc","repo":"slimphp/Slim","slug":"cannot-create-routecontext-before-routing-has-been","errorCode":null,"errorMessage":"Cannot create RouteContext before routing has been completed","messagePattern":"Cannot create RouteContext before routing has been completed","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"Slim/Routing/RouteContext.php","lineNumber":37,"sourceCode":"final class RouteContext\n{\n    public const ROUTE = '__route__';\n\n    public const ROUTE_PARSER = '__routeParser__';\n\n    public const ROUTING_RESULTS = '__routingResults__';\n\n    public const BASE_PATH = '__basePath__';\n\n    public static function fromRequest(ServerRequestInterface $serverRequest): self\n    {\n        $route = $serverRequest->getAttribute(self::ROUTE);\n        $routeParser = $serverRequest->getAttribute(self::ROUTE_PARSER);\n        $routingResults = $serverRequest->getAttribute(self::ROUTING_RESULTS);\n        $basePath = $serverRequest->getAttribute(self::BASE_PATH);\n\n        if ($routeParser === null || $routingResults === null) {\n            throw new RuntimeException('Cannot create RouteContext before routing has been completed');\n        }\n\n        /** @var RouteInterface|null $route */\n        /** @var RouteParserInterface $routeParser */\n        /** @var RoutingResults $routingResults */\n        /** @var string|null $basePath */\n        return new self($route, $routeParser, $routingResults, $basePath);\n    }\n\n    private ?RouteInterface $route;\n\n    private RouteParserInterface $routeParser;\n\n    private RoutingResults $routingResults;\n\n    private ?string $basePath;\n\n    private function __construct(","sourceCodeStart":19,"sourceCodeEnd":55,"githubUrl":"https://github.com/slimphp/Slim/blob/80900fb39cafce3ae53b18a2c4f642a122f03095/Slim/Routing/RouteContext.php#L19-L55","documentation":"RouteContext::fromRequest() builds the context from request attributes (__routeParser__ and __routingResults__) that only Slim's RoutingMiddleware writes onto the request while performing routing. If either attribute is absent, routing has not run yet for this request, so the helper refuses to construct a context. The error is therefore an execution-order problem: your code ran before routing, not a routing failure itself.","triggerScenarios":"Calling RouteContext::fromRequest($request) inside an app-level middleware that executes before RoutingMiddleware. In Slim 4 the last middleware added via $app->add() runs first (outermost), so adding your middleware AFTER $app->addRoutingMiddleware() in code makes yours execute before routing. Also triggered when RoutingMiddleware is never added (RouteRunner only performs routing at the innermost tip, after all middleware) or in tests that call $app->handle() on a request that skipped routing.","commonSituations":"Middleware that generates URLs (menus, pagination, API links) calling fromRequest() but registered in the wrong order relative to $app->addRoutingMiddleware(); refactoring from route-level middleware to app-level middleware; unit tests constructing ServerRequests from globals without running performRouting(); upgrading from Slim 3 where $app->request->getRouteInfo() habits carried over.","solutions":["Reorder the stack: call $app->addRoutingMiddleware() as the LAST add* statement, so routing wraps and runs before any middleware that needs RouteContext (last added = executed first)","Alternatively attach the middleware to specific routes or groups instead of app level — route middleware runs after routing by definition","In tests, run $routingMiddleware->performRouting($request) (or add the middleware) before asserting on RouteContext","If RoutingMiddleware is not added at all, add it — relying on RouteRunner means routing happens only at the innermost tip, after every app middleware"],"exampleFix":"// before — NavMiddleware added last runs FIRST, before routing: attributes missing\n$app->addRoutingMiddleware();\n$app->add(new NavMiddleware()); // RouteContext::fromRequest() throws\n\n// after — routing middleware added last = runs first (outermost)\n$app->add(new NavMiddleware());\n$app->addRoutingMiddleware();","handlingStrategy":"validation","validationCode":"use Slim\\Routing\\RouteContext;\n\nfunction routingCompleted(Psr\\Http\\Message\\ServerRequestInterface $request): bool\n{\n    return $request->getAttribute(RouteContext::ROUTE_PARSER) !== null\n        && $request->getAttribute(RouteContext::ROUTING_RESULTS) !== null;\n}\n\n// inside middleware, before using the context:\nif (!routingCompleted($request)) {\n    // either re-order the middleware stack, or route explicitly:\n    $request = $routingMiddleware->performRouting($request);\n}\n$context = RouteContext::fromRequest($request);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Standardize stack assembly: $app->addRoutingMiddleware() always the last add* call in bootstrap, so routing runs before all middleware that read route attributes","Wrap RouteContext::fromRequest() in a small app-level helper that checks the attributes first and fails with 'routing not run — check middleware order'","In tests, run performRouting() or the routing middleware before touching RouteContext","Code-review rule: any middleware calling RouteContext must sit after routing in the execution order"],"tags":["slim","php","middleware","routing","request-attributes","ordering"],"backgroundTag":"middleware-ordering","analyzedSha":"80900fb39cafce3ae53b18a2c4f642a122f03095","analyzedAt":"2026-08-21T01:41:09.580Z","schemaVersion":2},"datasetVersion":"2026-08-21T03:17:12.404Z"}