Lesson 8 / 26
Error Handling
HTTPException and custom handlers.
Map domain errors to responses
Raise HTTPException(status_code, detail) for simple cases. For domain errors (out of stock, payment declined), define exception classes and register exception handlers that convert them to consistent JSON responses with the right status (409 Conflict, 402, 404). Keep error bodies stable for clients, log unexpected exceptions with context, and never return stack traces.
Errors, tests, data
Consistent errors, overridable dependencies for tests, and a database layer complete a FastAPI service.
A domain exception mapped to 409, run
I ran this with Python 3.12, FastAPI 0.142.2, Pydantic 2.13 and Starlette 1.7, calling the app through FastAPI's TestClient (no server needed). A normal order succeeds; OutOfStock is converted by its handler into a 409 response; an unknown item raises HTTPException 404.
from fastapi import FastAPI, HTTPException, Request
from fastapi.responses import JSONResponse
from fastapi.testclient import TestClient
class OutOfStock(Exception):
def __init__(self, item: str):
self.item = item
app = FastAPI()
@app.exception_handler(OutOfStock)
async def out_of_stock_handler(request: Request, exc: OutOfStock):
return JSONResponse(status_code=409, content={"error": "out_of_stock", "item": exc.item})
@app.post("/orders/{item}")
def order(item: str):
if item == "lamp":
raise OutOfStock(item)
if item not in {"pen", "ink"}:
raise HTTPException(status_code=404, detail=f"Unknown item {item}")
return {"ordered": item}
client = TestClient(app)
for item in ["pen", "lamp", "rocket"]:
r = client.post(f"/orders/{item}")
print(r.status_code, r.json())
Output:
200 {'ordered': 'pen'}
409 {'error': 'out_of_stock', 'item': 'lamp'}
404 {'detail': 'Unknown item rocket'}Use a consistent error shape
Pick one error format (for example RFC 9457 problem details) for all endpoints so clients handle errors uniformly.
Quick check: Which status fits "item is out of stock" for an order request?
- 500 Internal Server Error
- 200 OK
- 409 Conflict
- 301 Moved Permanently
Answer
409 Conflict — The request conflicts with current state.