Skip to main content

Tutorial: Handling Your First Error

In this tutorial, you will learn how to use HTTPException to communicate errors back to your API clients. By the end of this guide, you will have built a small API that validates requests and returns meaningful error messages, status codes, and custom headers.

Prerequisites

To follow this tutorial, you need to have FastAPI installed. You can find the core exception class in fastapi.exceptions.HTTPException.

Step 1: Raising a Basic 404 Error

The most common use case for HTTPException is returning a "Not Found" error when a requested resource does not exist.

Create a file named main.py and add the following code from docs_src/handling_errors/tutorial001_py310.py:

from fastapi import FastAPI, HTTPException

app = FastAPI()

items = {"foo": "The Foo Wrestlers"}


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

How it works

  1. Import HTTPException: You import it directly from fastapi.
  2. Raise the Exception: When the item_id is not in the items dictionary, you raise the exception.
  3. Termination: Raising the exception immediately stops the execution of the path operation function. It doesn't return the dictionary at the end; instead, it sends the error response to the client.
  4. Response: The client receives an HTTP status code of 404 and a JSON body: {"detail": "Item not found"}.

Step 2: Providing Structured Error Details

The detail parameter is not limited to strings. You can pass any object that is JSON-serializable, such as a dictionary or a list. This is useful for providing machine-readable error codes or extra context.

Modify your endpoint to return a structured error:

@app.get("/items-structured/{item_id}")
async def read_item_structured(item_id: str):
if item_id not in items:
raise HTTPException(
status_code=404,
detail={
"error_code": "ITEM_MISSING",
"message": f"Item '{item_id}' was not found in the database.",
"suggestion": "Check the item ID and try again."
}
)
return {"item": items[item_id]}

When this error is raised, the client will receive the dictionary inside the detail key of the JSON response.

Step 3: Adding Custom Headers

Sometimes you need to include custom HTTP headers in your error response. This is common in security scenarios (like WWW-Authenticate) or for custom debugging information.

Use the following pattern from docs_src/handling_errors/tutorial002_py310.py:

@app.get("/items-header/{item_id}")
async def read_item_header(item_id: str):
if item_id not in items:
raise HTTPException(
status_code=404,
detail="Item not found",
headers={"X-Error": "There goes my error"},
)
return {"item": items[item_id]}

The headers parameter accepts a dictionary of strings. These will be included in the HTTP response sent to the client alongside the status code and body.

Step 4: Using HTTPException in Dependencies

One of the most powerful features of HTTPException is that it can be raised from anywhere in the request flow, including inside dependencies. If a dependency raises an HTTPException, the path operation function will never be called.

This is frequently used for authentication, as seen in docs_src/security/tutorial003_an_py310.py:

from typing import Annotated
from fastapi import Depends, FastAPI, HTTPException, status

app = FastAPI()

async def get_current_user(token: str):
# In a real app, you would decode and validate the token here
user_exists = False
if not user_exists:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Not authenticated",
headers={"WWW-Authenticate": "Bearer"},
)
return {"username": "fakeuser"}

@app.get("/users/me")
async def read_users_me(current_user: Annotated[dict, Depends(get_current_user)]):
return current_user

Why this is useful

  • Security: You can centralize your authentication logic. If the token is invalid, the HTTPException is raised, and the request is terminated before it ever reaches your sensitive route logic.
  • Reusability: You can use the same dependency across multiple routes, and they will all handle errors consistently.

Summary

You have now built an API that:

  • Uses HTTPException to return standard HTTP error codes.
  • Provides detailed, structured JSON error messages.
  • Includes custom HTTP headers in error responses.
  • Handles errors gracefully within dependencies to protect your routes.

For more advanced scenarios, you can create custom exception handlers to override how HTTPException is rendered globally across your entire application.