slimphp/Slim · error · RuntimeException

No base path defined.

Error message

No base path defined.

What it means

RouteContext::getBasePath() returns the __basePath__ request attribute, which in a standard Slim app is only set by RouteRunner — the innermost handler — right before it invokes the matched route. If the attribute is null, the context was created from a request that never passed through RouteRunner, so no base path is known and this RuntimeException is thrown. Note RoutingMiddleware sets the parser and routing results but not the base path, so fromRequest() can succeed while getBasePath() still fails.

Source

Thrown at Slim/Routing/RouteContext.php:85

    public function getRoute(): ?RouteInterface
    {
        return $this->route;
    }

    public function getRouteParser(): RouteParserInterface
    {
        return $this->routeParser;
    }

    public function getRoutingResults(): RoutingResults
    {
        return $this->routingResults;
    }

    public function getBasePath(): string
    {
        if ($this->basePath === null) {
            throw new RuntimeException('No base path defined.');
        }
        return $this->basePath;
    }
}

View on GitHub (pinned to 80900fb39c)

Solutions

  1. Move the getBasePath() call into the route handler or route-level middleware, where RouteRunner has already set the attribute
  2. In app middleware, read $request->getAttribute(RouteContext::BASE_PATH) and treat null as empty instead of calling getBasePath()
  3. If the app is served from a subdirectory, configure it once via $app->setBasePath('/subdir') — but note this alone does not make the attribute available in pre-RouteRunner middleware
  4. In tests, seed the attribute explicitly: $request = $request->withAttribute(RouteContext::BASE_PATH, '/subdir')

Example fix

// before — app-level middleware, runs before RouteRunner sets __basePath__
$basePath = RouteContext::fromRequest($request)->getBasePath(); // throws 'No base path defined.'

// after — null-safe attribute read, works at any middleware layer
$basePath = $request->getAttribute(RouteContext::BASE_PATH) ?? '';
Defensive patterns

Strategy: validation

Validate before calling

use Slim\Routing\RouteContext;

// works at any layer; BASE_PATH is set by RouteRunner before the route handler runs
$basePathAttr = $request->getAttribute(RouteContext::BASE_PATH);
if (is_string($basePathAttr)) {
    $basePath = $basePathAttr;
} else {
    // routing done but RouteRunner not reached (app middleware) — use configured value or default
    $basePath = '';
}

Try / catch

try {
    $basePath = $context->getBasePath();
} catch (RuntimeException $e) {
    // only reachable when the attribute is absent (e.g. pre-RouteRunner middleware)
    $basePath = '';
}

Prevention

When it happens

Trigger: Calling RouteContext::fromRequest($request)->getBasePath() inside app-level middleware (even after routing middleware ran), because the BASE_PATH attribute is attached later by RouteRunner; reading it in middleware executed before RouteRunner; building RouteContext in unit tests from a request whose attributes were seeded manually without BASE_PATH; replacing RouteRunner with a custom RequestHandler that does not set the attribute.

Common situations: Link-builder or breadcrumb middleware that wants the base path for absolute URLs; middleware refactors where code moved out of a route handler into app middleware; test harnesses that craft requests from ServerRequestCreatorFactory without running the full kernel; custom micro-kernels using App as a component without RouteRunner's proxy.

Related errors


AI-assisted analysis of slimphp/Slim@80900fb39c (2026-08-21). Data as JSON: /api/errors/7e53788dfb3b525a. Report an issue: GitHub.