tiangolo/fastapi · error · HTTPException

Not authorized

Error message

Not authorized

What it means

Same HTTP 403 "Not authorized" as error 32, but in tutorial014 the `get_user` dependency additionally calls `session.close()` after the not-found check. The 403 is raised before session.close(), so the response is identical to 00813; the close is there to demonstrate explicit cleanup within a dependency that uses an externally-managed session.

Source

Thrown at docs_src/dependencies/tutorial014_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")
    session.close()


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

  1. Pass an existing user_id.
  2. Ensure the User table is created and seeded.
  3. Do not close the session before the StreamingResponse if later code needs it; let the session dependency manage its lifecycle.
  4. Prefer 404 if existence-leak is acceptable.

Example fix

# before
user = session.get(User, user_id)
if not user:
    raise HTTPException(status_code=403, detail="Not authorized")
session.close()

# after
user = session.get(User, user_id)
if not user:
    raise HTTPException(status_code=403, detail="Not authorized")
# let get_session's `with` block close the session
Defensive patterns

Strategy: validation

Validate before calling

if session.get(User, user_id) is None:
    raise PermissionError("Not authorized")
# only then issue the /generate request

Type guard

def authorized(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:
    # surface login/permission flow
    ...

Prevention

When it happens

Trigger: GET /generate with a user_id that does not resolve to a User row, under the tutorial014 dependency.

Common situations: Same as error 32; specifically when the dependency manually closes the session before the StreamingResponse consumes it (which can cause issues if the stream needs the session).

Related errors


AI-assisted analysis of tiangolo/fastapi@42a41db11f (2026-08-04). Data as JSON: /data/errors/58795996f2171dd9.json. Report an issue: GitHub.