tiangolo/fastapi · error · AssertionError

A frontend path must start with '/'

Error message

A frontend path must start with '/'

What it means

`_normalize_frontend_path` (routing.py:1856-1857) raises `AssertionError` when the path does not start with `/`. URL path prefixes must be absolute in ASGI routing, so a relative-looking frontend path is rejected at construction time inside `APIRouter.frontend()` (routing.py:2704).

Source

Thrown at fastapi/routing.py:1857

                yield RouteContext(original_route, route_context)


def _iter_routes_with_context(
    routes: Sequence[BaseRoute],
) -> Iterator[tuple[BaseRoute, _EffectiveRouteContext | None]]:
    for route in routes:
        if isinstance(route, _IncludedRouter):
            for route_context in route.effective_route_contexts():
                yield route_context.original_route, route_context
        else:
            yield route, None


def _normalize_frontend_path(path: str) -> str:
    if not path:
        raise AssertionError("A frontend path cannot be empty")
    if not path.startswith("/"):
        raise AssertionError("A frontend path must start with '/'")
    if path != "/":
        path = path.rstrip("/")
    return path


def _join_frontend_paths(prefix: str, path: str) -> str:
    if not prefix:
        return path
    if path == "/":
        return prefix
    return prefix + path


def _frontend_path_specificity(path: str) -> int:
    if path == "/":
        return 0
    return len(path)

View on GitHub (pinned to 42a41db11f)

Solutions

  1. Prefix the path with `/` before calling `.frontend()` (e.g. `f"/{name.lstrip('/')}"`).
  2. Use `"/"` for root or `"/<segment>"` for a sub-mount.
  3. Normalize config-driven paths in one place so the value always starts with `/`.

Example fix

# before
app.frontend("app", directory="dist")

# after
app.frontend("/app", directory="dist")
Defensive patterns

Strategy: validation

Validate before calling

def normalize_frontend_path(path: str) -> str:
    if not path:
        raise ValueError("frontend path cannot be empty")
    if not path.startswith("/"):
        path = "/" + path.lstrip("/")
    return path

# usage
app.frontend(normalize_frontend_path(raw_path), directory="dist")

Type guard

def is_absolute_frontend_path(path: object) -> bool:
    return isinstance(path, str) and path.startswith("/")

Prevention

When it happens

Trigger: Calling `app.frontend("app", directory="dist")` (missing leading slash) or any `.frontend(path)` where path is e.g. `"static"`, `"spa"`, or `"/"` stripped by mistake.

Common situations: Stripping a leading `/` via `path.lstrip("/")` or `path.strip()` before passing it; building the path from a route name without normalizing; reading a prefix from config stored without the slash.

Related errors


AI-assisted analysis of tiangolo/fastapi@42a41db11f (2026-08-04). Data as JSON: /data/errors/a554f22b66fa841c.json. Report an issue: GitHub.