{"record":{"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/3e8d1526d83a90aaf7d6eb6dc682bf150f180b25/fastapi/routing.py#L1839-L1875","documentation":"Raised by `_normalize_frontend_path` (fastapi/routing.py:1857) when `path` is non-empty but does not start with '/'. FastAPI route paths (including frontend mount paths) are URL paths and must be absolute, so a relative-looking value like 'app' or 'frontend' is rejected at setup time with an AssertionError.","triggerScenarios":"Calling `router.frontend('app', directory='dist')`, `router.frontend('frontend/', directory='dist')`, or any value whose first character is not '/'. Building the path by concatenation that drops the leading slash (e.g. `frontend(env_base.lstrip('/'), ...)`).","commonSituations":"Reusing a filesystem directory name as the URL path without a leading slash. Reading a path from config/env that was stored without '/'. Constructing a prefix dynamically and forgetting to prepend '/'.","solutions":["Prefix the value with '/': `router.frontend('/' + value.lstrip('/'), directory='dist')`.","Use the conventional '/' to mount at the app root: `router.frontend('/', directory='dist')`.","Validate the value at startup: `assert path.startswith('/')` before calling `frontend`."],"exampleFix":"// before\nrouter.frontend('app', directory='dist')\n// after\nrouter.frontend('/app', directory='dist')","handlingStrategy":"validation","validationCode":"def normalize_frontend_path(path: str) -> str:\n    if not path.startswith('/'):\n        path = '/' + path.lstrip('/')\n    return path\n\nrouter.frontend(normalize_frontend_path(raw), directory='dist')","typeGuard":"def is_absolute_frontend_path(path: object) -> bool:\n    return isinstance(path, str) and path.startswith('/')","tryCatchPattern":null,"preventionTips":["Always prefix frontend paths with '/'.","Centralize path normalization in a helper used by every frontend(...) call.","Assert path.startswith('/') in tests."],"tags":["fastapi","frontend-routing","configuration","assertion"],"backgroundTag":null,"analyzedSha":"3e8d1526d83a90aaf7d6eb6dc682bf150f180b25","analyzedAt":"2026-08-11T02:34:52.986Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}