tiangolo/fastapi · error · HTTPException
Not authorized
Error message
Not authorized
What it means
FastAPI returns HTTP 403 "Not authorized" when `session.get(User, user_id)` returns no row for the given id. The handler deliberately uses 403 rather than 404 to avoid leaking which user ids exist. The dependency is attached to the /generate route via `dependencies=[Depends(get_user)]`, so it runs before the StreamingResponse begins.
Source
Thrown at docs_src/dependencies/tutorial013_an_py310.py:27
class User(SQLModel, table=True):
id: int | None = Field(default=None, primary_key=True)
name: str
app = FastAPI()
def get_session():
with Session(engine) as session:
yield session
def get_user(user_id: int, session: Annotated[Session, Depends(get_session)]):
user = session.get(User, user_id)
if not user:
raise HTTPException(status_code=403, detail="Not authorized")
def generate_stream(query: str):
for ch in query:
yield ch
time.sleep(0.1)
@app.get("/generate", dependencies=[Depends(get_user)])
def generate(query: str):
return StreamingResponse(content=generate_stream(query))
View on GitHub (pinned to 42a41db11f)
Solutions
- Supply a user_id that exists in the User table (create it first if needed).
- Run SQLModel metadata creation / migrations so the table is populated.
- Verify the engine URL points at the intended database.
- If leaking existence is acceptable for your threat model, switch to 404 for clarity.
Example fix
# before
user = session.get(User, user_id)
if not user:
raise HTTPException(status_code=403, detail="Not authorized")
# after (optional, if 404 semantics preferred)
user = session.get(User, user_id)
if not user:
raise HTTPException(status_code=404, detail="User not found") Defensive patterns
Strategy: validation
Validate before calling
# Verify user existence before calling /generate
exists = users_table.get(user_id)
if not exists:
raise PermissionError("Not authorized")
client.get("/generate", params={"user_id": user_id, "query": q}) Type guard
def user_exists(session, user_id: int) -> bool:
return session.get(User, user_id) is not None Try / catch
r = client.get("/generate", params={...})
if r.status_code == 403:
# treat as unknown/unauthorized user; do not leak existence
... Prevention
- Seed/confirm the user row before relying on the endpoint.
- Ensure DB migrations created the User table.
- Keep 403 vs 404 decision deliberate to avoid user enumeration.
When it happens
Trigger: GET /generate?query=...&user_id=<nonexistent> (or where the user_id query param does not map to a persisted User row).
Common situations: Clients passing an unauthenticated/typo'd user_id; the DB has no matching row; the SQLModel table not created/migrated; wrong DB connection string pointing at an empty database.
Related errors
AI-assisted analysis of tiangolo/fastapi@42a41db11f (2026-08-04).
Data as JSON: /data/errors/6aa684c6d42f364a.json.
Report an issue: GitHub.