tiangolo/fastapi · error · AssertionError

A frontend path cannot be empty

Error message

A frontend path cannot be empty

What it means

`_normalize_frontend_path` (routing.py:1853-1860) rejects an empty path with `AssertionError`. It is called by `APIRouter.frontend()` (routing.py:2704) when you register a static frontend mount. The path is the URL prefix under which the built frontend is served, and an empty prefix is ambiguous, so FastAPI aborts at router/app construction time.

Source

Thrown at fastapi/routing.py:1855

                yield RouteContext(original_route)
            else:
                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

View on GitHub (pinned to 42a41db11f)

Solutions

  1. Pass a non-empty path beginning with `/`, typically `"/"` for a root-mounted SPA.
  2. If the mount point is configurable, default it to `"/"` and validate before calling `.frontend(...)`.
  3. Check for empty/None before invoking `.frontend()` and raise a clear config error of your own.

Example fix

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

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

Strategy: validation

Validate before calling

def assert_frontend_path(path: str) -> str:
    if not isinstance(path, str) or path == "":
        raise ValueError("frontend path must be a non-empty string starting with '/'")
    if not path.startswith("/"):
        path = "/" + path.lstrip("/")
    return path

# usage
fp = assert_frontend_path(config.get("FRONTEND_PATH", "/"))
app.frontend(fp, directory="dist")

Type guard

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

Prevention

When it happens

Trigger: Calling `app.frontend("", directory="dist")` or `router.frontend("", directory=...)`. Passing a computed path variable that resolves to `""`.

Common situations: Building the path from config/env that is unset and defaults to empty; copy-pasting an example but forgetting the leading segment; dynamically composing `f"{base}"` where base is empty.

Related errors


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