{"record":{"id":"58795996f2171dd9","repo":"tiangolo/fastapi","slug":"not-authorized-587959","errorCode":null,"errorMessage":"Not authorized","messagePattern":"Not authorized","errorType":"http","errorClass":"HTTPException","httpStatus":403,"severity":"error","filePath":"docs_src/dependencies/tutorial014_an_py310.py","lineNumber":27,"sourceCode":"\n\nclass User(SQLModel, table=True):\n    id: int | None = Field(default=None, primary_key=True)\n    name: str\n\n\napp = FastAPI()\n\n\ndef get_session():\n    with Session(engine) as session:\n        yield session\n\n\ndef get_user(user_id: int, session: Annotated[Session, Depends(get_session)]):\n    user = session.get(User, user_id)\n    if not user:\n        raise HTTPException(status_code=403, detail=\"Not authorized\")\n    session.close()\n\n\ndef generate_stream(query: str):\n    for ch in query:\n        yield ch\n        time.sleep(0.1)\n\n\n@app.get(\"/generate\", dependencies=[Depends(get_user)])\ndef generate(query: str):\n    return StreamingResponse(content=generate_stream(query))\n","sourceCodeStart":9,"sourceCodeEnd":40,"githubUrl":"https://github.com/tiangolo/fastapi/blob/3e8d1526d83a90aaf7d6eb6dc682bf150f180b25/docs_src/dependencies/tutorial014_an_py310.py#L9-L40","documentation":"Same HTTPException(403) 'Not authorized' as error 30 but in tutorial014_an_py310, which additionally calls session.close() after the not-found check. The dependency closes the session and then raises; the streaming generator then runs without an open session. Same trigger: a user_id with no matching User row.","triggerScenarios":"GET /generate?query=...&user_id=<id> where the User row does not exist. The session is explicitly closed before the HTTPException is raised.","commonSituations":"Streaming endpoints where the session must be closed early to avoid holding a DB connection during a long stream. Developers hit the 403 when the user_id is wrong/absent, or when closing the session breaks later lazy loads.","solutions":["Provide a user_id that exists in the User table.","Verify the DB connection and that the table is seeded.","If session.close() causes issues downstream (e.g. lazy access in the stream), refactor to manage the session lifecycle explicitly around the stream."],"exampleFix":"// before\nuser = session.get(User, user_id)\nif not user:\n    raise HTTPException(status_code=403, detail=\"Not authorized\")\nsession.close()\n// after\nuser = session.get(User, user_id)\nif not user:\n    raise HTTPException(status_code=404, detail=\"User not found\")\nsession.close()","handlingStrategy":"validation","validationCode":"with Session(engine) as s:\n    assert s.get(User, user_id) is not None, 'user missing -> 403'","typeGuard":"def user_exists(session, user_id: int) -> bool:\n    return session.get(User, user_id) is not None","tryCatchPattern":"resp = requests.get('http://localhost:8000/generate', params={'query': q, 'user_id': uid})\nif resp.status_code == 403:\n    print('Not authorized (user missing)')","preventionTips":["Ensure user rows are seeded.","Avoid lazy DB access after session.close() in the stream.","Use 404 for not-found to avoid conflating with authorization."],"tags":["fastapi","http-403","sqlmodel","streaming","session-management"],"backgroundTag":null,"analyzedSha":"3e8d1526d83a90aaf7d6eb6dc682bf150f180b25","analyzedAt":"2026-08-11T02:34:52.986Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}