Complete DevOps Bootcamp: Master DevOps in 12 Weeks
FastAPIResponse Handling and Errors

Raising HTTPException

Introduction

HTTPException is FastAPI's built-in way to return an error response from anywhere in your code. Raising it stops the current request, sets the appropriate status code, and sends a JSON body describing the problem.

Why This Matters

Errors should be explicit and easy to produce. Without HTTPException, you would either build error responses by hand in every route or let exceptions bubble up as 500s. HTTPException keeps error logic short, consistent, and well-documented.

Basic Usage

Import HTTPException and raise it with a status code and detail message:

from fastapi import FastAPI, HTTPException

app = FastAPI()

items = {1: "Pen", 2: "Notebook"}

@app.get("/items/{item_id}")
def get_item(item_id: int):
    if item_id not in items:
        raise HTTPException(status_code=404, detail="Item not found")
    return {"item_id": item_id, "name": items[item_id]}

A request to /items/99 returns:

{
  "detail": "Item not found"
}

with status code 404.

Using Status Constants

For readability, pair HTTPException with the status module:

from fastapi import HTTPException, status

raise HTTPException(
    status_code=status.HTTP_404_NOT_FOUND,
    detail="Item not found",
)

Structured Detail

The detail field can be a dict or list, not just a string:

@app.post("/orders")
def create_order(quantity: int):
    if quantity <= 0:
        raise HTTPException(
            status_code=400,
            detail={
                "code": "invalid_quantity",
                "message": "Quantity must be positive",
                "field": "quantity",
            },
        )
    return {"quantity": quantity}

Structured details help clients react programmatically rather than parsing strings.

Adding Custom Headers

Some error responses need headers. The most common case is WWW-Authenticate for 401s:

@app.get("/secret")
def get_secret(token: str | None = None):
    if token != "valid":
        raise HTTPException(
            status_code=401,
            detail="Not authenticated",
            headers={"WWW-Authenticate": "Bearer"},
        )
    return {"secret": "FastAPI rocks"}

The header is included in the response alongside the body.

Raising From Helper Functions

HTTPException works from anywhere in the call stack - services, repositories, dependencies - not just route functions:

def find_item(item_id: int):
    if item_id not in items:
        raise HTTPException(status_code=404, detail="Item not found")
    return items[item_id]

@app.get("/items/{item_id}")
def get_item(item_id: int):
    return {"item_id": item_id, "name": find_item(item_id)}

The exception bubbles up through the framework, which converts it into the proper HTTP response.

Choosing the Right Status Code

SituationStatus code
Resource does not exist404
Authentication required or failed401
Authenticated but not allowed403
Invalid input that schema validation cannot catch400 or 422
State conflict, like a duplicate409
Rate limited429
Service is down or dependency failed503

Use the most specific code that applies. Reserve 500 for unexpected server-side bugs.

Combining With Validation

Pydantic handles request shape and type errors automatically with 422. Use HTTPException for business rules that go beyond validation:

@app.post("/transfers")
def transfer_money(from_id: int, to_id: int, amount: float):
    if amount <= 0:
        raise HTTPException(status_code=422, detail="Amount must be positive")
    if from_id == to_id:
        raise HTTPException(status_code=400, detail="Cannot transfer to self")
    # do the transfer
    return {"status": "ok"}

Both layers can coexist on the same endpoint.

Common Mistakes

Returning errors instead of raising them

Returning {"error": "..."} with a 200 status hides failures from the client. Always raise HTTPException so the status code reflects the result.

Using 500 for client errors

500 means "we crashed". Bad input, missing resources, and forbidden actions are not 500s. Pick the proper 4xx code.

Leaking internal information

Avoid putting stack traces, SQL errors, or internal IDs in the detail field. They expose implementation details and may help attackers.

Summary

Raise HTTPException with a status code and detail to send a clean error response from anywhere in your code. Use structured details for machine-readable errors and add headers when the protocol requires them. Match status codes to what really happened so clients and tools can react correctly.

How is this guide?

Last updated on