{"record":{"id":"0e901746b13c342a","repo":"tiangolo/fastapi","slug":"owner-error-e","errorCode":null,"errorMessage":"Owner error: {e}","messagePattern":"Owner error: (.+?)","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"error","filePath":"docs_src/dependencies/tutorial008b_an_py310.py","lineNumber":22,"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: Annotated[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":4,"sourceCodeEnd":33,"githubUrl":"https://github.com/tiangolo/fastapi/blob/3e8d1526d83a90aaf7d6eb6dc682bf150f180b25/docs_src/dependencies/tutorial008b_an_py310.py#L4-L33","documentation":"Raised (400) inside the get_username yield-dependency's except block. The endpoint get_item raises OwnerError(username) (a custom Exception) when the item's owner != the yielded username ('Rick'). FastAPI catches exceptions thrown during a yield-dependency's cleanup and lets the dependency re-raise them as HTTPException. detail is an f-string embedding the exception message, so it reads 'Owner error: Rick'.","triggerScenarios":"GET /items/plumbus (owner 'Morty') when the dependency yields username 'Rick'. The owner mismatch at line 30 raises OwnerError('Rick'), which propagates into the dependency's except block and becomes a 400.","commonSituations":"Developers misuse yield-dependencies for authorization: the check happens in the endpoint, but the HTTPException is raised in the dependency, which is confusing. Also, because the f-string interpolates arbitrary exception text, it can leak internal identifiers if OwnerError is raised with sensitive data.","solutions":["Request an item owned by the yielded user: GET /items/portal-gun (owner 'Rick') instead of /items/plumbus.","Move the ownership check into the dependency itself (pre-yield) so authorization fails before the endpoint runs.","Avoid interpolating raw exception messages into user-visible detail to prevent information leakage."],"exampleFix":"// before\nGET /items/plumbus   (owner Morty, user Rick -> OwnerError)\n// after\nGET /items/portal-gun (owner Rick, user Rick -> 200)","handlingStrategy":"try-catch","validationCode":"import httpx\nOWNERS = {'plumbus': 'Morty', 'portal-gun': 'Rick'}\nUSER = 'Rick'\ndef readable_for(user: str) -> list[str]:\n    return [k for k, v in OWNERS.items() if v == user]\n# choose an item owned by Rick\nitem_id = 'portal-gun'\nresp = httpx.get(f'http://localhost:8000/items/{item_id}')","typeGuard":"def is_owned_by(item_id: object, user: str) -> bool:\n    return isinstance(item_id, str) and OWNERS.get(item_id) == user","tryCatchPattern":"try:\n    resp = httpx.get(f'http://localhost:8000/items/{item_id}')\n    resp.raise_for_status()\nexcept httpx.HTTPStatusError as e:\n    if e.response.status_code == 400 and 'Owner error' in e.response.text:\n        # access denied for this owner; pick another item or surface to user\n        ...","preventionTips":["Request only items owned by the yielded user.","Prefer running authorization in a pre-yield dependency so it fails early.","Do not interpolate raw exception text into user-visible detail."],"tags":["fastapi","yield-dependency","authorization","custom-exception","dependencies-tutorial"],"backgroundTag":null,"analyzedSha":"3e8d1526d83a90aaf7d6eb6dc682bf150f180b25","analyzedAt":"2026-08-11T02:34:52.986Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}