{"record":{"id":"6aa684c6d42f364a","repo":"tiangolo/fastapi","slug":"not-authorized","errorCode":null,"errorMessage":"Not authorized","messagePattern":"Not authorized","errorType":"http","errorClass":"HTTPException","httpStatus":403,"severity":"error","filePath":"docs_src/dependencies/tutorial013_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\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":39,"githubUrl":"https://github.com/tiangolo/fastapi/blob/3e8d1526d83a90aaf7d6eb6dc682bf150f180b25/docs_src/dependencies/tutorial013_an_py310.py#L9-L39","documentation":"HTTPException (403) raised inside the get_user dependency used by the streaming endpoint GET /generate. It looks up a User by user_id in the database via SQLModel; if no row is found, it raises 'Not authorized'. The dependency is attached via dependencies=[Depends(get_user)], so it runs before the streaming response begins. Note this returns 403 rather than the more conventional 401/404, conflating 'not found' with 'forbidden' for access-control purposes.","triggerScenarios":"GET /generate?query=...&user_id=<id> where no User row with that id exists in the postgres database. The dependency requires user_id (an int query/path parameter).","commonSituations":"Streaming endpoints gated by ownership checks. Developers hit this when the user_id is absent (then a 422 for missing param), points at a deleted/nonexistent user, or the database is unreachable (then a different connection error). Also seen when the DB is not seeded.","solutions":["Ensure the user_id corresponds to an existing User row (seed the database).","Confirm the postgres connection string postgresql+psycopg://postgres:postgres@localhost/db is reachable and the table exists.","If a missing user should be 404 rather than 403, change the status code and detail accordingly."],"exampleFix":"// before\nuser = session.get(User, user_id)\nif not user:\n    raise HTTPException(status_code=403, detail=\"Not authorized\")\n// after\nuser = session.get(User, user_id)\nif not user:\n    raise HTTPException(status_code=404, detail=\"User not found\")","handlingStrategy":"validation","validationCode":"from sqlmodel import Session, create_engine\nengine = create_engine('postgresql+psycopg://postgres:postgres@localhost/db')\nwith Session(engine) as s:\n    exists = s.get(User, user_id) is not None\nassert exists, f'user {user_id} missing'","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('user not authorized/missing')","preventionTips":["Seed the DB with the user before calling.","Verify connectivity to postgres and table existence.","Consider 404 instead of 403 for missing users."],"tags":["fastapi","http-403","sqlmodel","streaming","authorization"],"backgroundTag":null,"analyzedSha":"3e8d1526d83a90aaf7d6eb6dc682bf150f180b25","analyzedAt":"2026-08-11T02:34:52.986Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}