tiangolo/fastapi · error · HTTPException

Not authorized

Error message

Not authorized

What it means

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.

Solutions

  1. Provide a user_id that exists in the User table.
  2. Verify the DB connection and that the table is seeded.
  3. If session.close() causes issues downstream (e.g. lazy access in the stream), refactor to manage the session lifecycle explicitly around the stream.

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=404, detail="User not found")
session.close()
Defensive patterns

Strategy: validation

Validate before calling

with Session(engine) as s:
    assert s.get(User, user_id) is not None, 'user missing -> 403'

Type guard

def user_exists(session, user_id: int) -> bool:
    return session.get(User, user_id) is not None

Try / catch

resp = requests.get('http://localhost:8000/generate', params={'query': q, 'user_id': uid})
if resp.status_code == 403:
    print('Not authorized (user missing)')

Prevention

When it happens

Trigger: GET /generate?query=...&user_id=<id> where the User row does not exist. The session is explicitly closed before the HTTPException is raised.

Common situations: 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.

Related errors


AI-assisted analysis of tiangolo/fastapi@3e8d1526d8 (2026-08-11). Data as JSON: /api/errors/58795996f2171dd9. Report an issue: GitHub.

Appendix: 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 3e8d1526d8)