{"id":"a554f22b66fa841c","repo":"tiangolo/fastapi","slug":"a-frontend-path-must-start-with","errorCode":null,"errorMessage":"A frontend path must start with '/'","messagePattern":"A frontend path must start with '/'","errorType":"exception","errorClass":"AssertionError","httpStatus":null,"severity":"error","filePath":"fastapi/routing.py","lineNumber":1857,"sourceCode":"                yield RouteContext(original_route, route_context)\n\n\ndef _iter_routes_with_context(\n    routes: Sequence[BaseRoute],\n) -> Iterator[tuple[BaseRoute, _EffectiveRouteContext | None]]:\n    for route in routes:\n        if isinstance(route, _IncludedRouter):\n            for route_context in route.effective_route_contexts():\n                yield route_context.original_route, route_context\n        else:\n            yield route, None\n\n\ndef _normalize_frontend_path(path: str) -> str:\n    if not path:\n        raise AssertionError(\"A frontend path cannot be empty\")\n    if not path.startswith(\"/\"):\n        raise AssertionError(\"A frontend path must start with '/'\")\n    if path != \"/\":\n        path = path.rstrip(\"/\")\n    return path\n\n\ndef _join_frontend_paths(prefix: str, path: str) -> str:\n    if not prefix:\n        return path\n    if path == \"/\":\n        return prefix\n    return prefix + path\n\n\ndef _frontend_path_specificity(path: str) -> int:\n    if path == \"/\":\n        return 0\n    return len(path)\n","sourceCodeStart":1839,"sourceCodeEnd":1875,"githubUrl":"https://github.com/tiangolo/fastapi/blob/42a41db11f6882807ac3c057b942178d53b97438/fastapi/routing.py#L1839-L1875","documentation":"`_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).","triggerScenarios":"Calling `app.frontend(\"app\", directory=\"dist\")` (missing leading slash) or any `.frontend(path)` where path is e.g. `\"static\"`, `\"spa\"`, or `\"/\"` stripped by mistake.","commonSituations":"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.","solutions":["Prefix the path with `/` before calling `.frontend()` (e.g. `f\"/{name.lstrip('/')}\"`).","Use `\"/\"` for root or `\"/<segment>\"` for a sub-mount.","Normalize config-driven paths in one place so the value always starts with `/`."],"exampleFix":"# before\napp.frontend(\"app\", directory=\"dist\")\n\n# after\napp.frontend(\"/app\", directory=\"dist\")","handlingStrategy":"validation","validationCode":"def normalize_frontend_path(path: str) -> str:\n    if not path:\n        raise ValueError(\"frontend path cannot be empty\")\n    if not path.startswith(\"/\"):\n        path = \"/\" + path.lstrip(\"/\")\n    return path\n\n# usage\napp.frontend(normalize_frontend_path(raw_path), directory=\"dist\")","typeGuard":"def is_absolute_frontend_path(path: object) -> bool:\n    return isinstance(path, str) and path.startswith(\"/\")","tryCatchPattern":null,"preventionTips":["Never `.strip()` or `.lstrip(\"/\")` a path right before passing it to `.frontend()`.","Centralize path construction so segments always carry their leading slash.","Add a startup assertion over all configured mounts."],"tags":["frontend","routing","configuration"],"analyzedSha":"42a41db11f6882807ac3c057b942178d53b97438","analyzedAt":"2026-08-04T19:23:32.007Z","schemaVersion":2}