{"id":"fc01ee80af6d9930","repo":"tiangolo/fastapi","slug":"owner-error-e-fc01ee","errorCode":null,"errorMessage":"Owner error: {e}","messagePattern":"Owner error: (.+?)","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"docs_src/dependencies/tutorial008b_py310.py","lineNumber":20,"sourceCode":"\napp = FastAPI()\n\n\ndata = {\n    \"plumbus\": {\"description\": \"Freshly pickled plumbus\", \"owner\": \"Morty\"},\n    \"portal-gun\": {\"description\": \"Gun to create portals\", \"owner\": \"Rick\"},\n}\n\n\nclass OwnerError(Exception):\n    pass\n\n\ndef get_username():\n    try:\n        yield \"Rick\"\n    except OwnerError as e:\n        raise HTTPException(status_code=400, detail=f\"Owner error: {e}\")\n\n\n@app.get(\"/items/{item_id}\")\ndef get_item(item_id: str, username: str = Depends(get_username)):\n    if item_id not in data:\n        raise HTTPException(status_code=404, detail=\"Item not found\")\n    item = data[item_id]\n    if item[\"owner\"] != username:\n        raise OwnerError(username)\n    return item\n","sourceCodeStart":2,"sourceCodeEnd":31,"githubUrl":"https://github.com/tiangolo/fastapi/blob/42a41db11f6882807ac3c057b942178d53b97438/docs_src/dependencies/tutorial008b_py310.py#L2-L31","documentation":"This is the HTTP 400 response that FastAPI returns to the client after the yield-based `get_username` dependency catches the OwnerError raised downstream in the path operation. The detail string interpolates the exception (`f\"Owner error: {e}\"`), surfacing whatever the OwnerError carried (here, the username). It illustrates how yield dependencies can translate internal exceptions into structured HTTP errors at the cleanup boundary.","triggerScenarios":"Any request to GET /items/{item_id} where item_id resolves to an item whose owner differs from \"Rick\" (e.g. \"plumbus\" owner=\"Morty\"); the handler raises OwnerError, which the dependency catches and re-raises as HTTPException(400).","commonSituations":"Ownership/authorization mismatch surfaced to clients; leaking internal principal names in detail strings; relying on a dependency to centralize error translation but forgetting it only fires for the specific exception type caught.","solutions":["Call the endpoint with credentials/items whose owner matches the dependency-yielded username.","Refine the detail to avoid leaking usernames: use a generic \"Not authorized\" message mapped to HTTP 403.","Ensure OwnerError is the only exception type swallowed by the dependency so unrelated errors are not masked.","Write a test that posts an unauthorized item_id and asserts the 400 payload shape."],"exampleFix":"# before\nexcept OwnerError as e:\n    raise HTTPException(status_code=400, detail=f\"Owner error: {e}\")\n\n# after\nexcept OwnerError:\n    raise HTTPException(status_code=403, detail=\"Not authorized\")","handlingStrategy":"try-catch","validationCode":"# Resolve the effective username before the call and skip items not owned by it\nif item_owner != effective_username:\n    raise PermissionError(f\"{effective_username} cannot read this item\")","typeGuard":"def owner_matches(item: dict, username: str) -> bool:\n    return isinstance(item, dict) and item.get(\"owner\") == username","tryCatchPattern":"try:\n    resp = client.get(f\"/items/{item_id}\")\nexcept httpx.HTTPStatusError:\n    ...\nelse:\n    if resp.status_code == 400 and \"Owner error\" in resp.text:\n        # surface an authorization prompt instead of retrying\n        ...","preventionTips":["Do not leak internal usernames in detail strings.","Map ownership denials to 403 in your own services.","Have clients treat 'Owner error' as terminal, not retryable."],"tags":["fastapi","dependencies","http-400","authorization","yield-dependency"],"analyzedSha":"42a41db11f6882807ac3c057b942178d53b97438","analyzedAt":"2026-08-04T19:23:32.007Z","schemaVersion":2}