DEV Community

Cover image for FastAPI for AI Engineers - Part 9: Mastering HTTP Exceptions & Status Codes
Ananya S
Ananya S

Posted on AI-assisted

FastAPI for AI Engineers - Part 9: Mastering HTTP Exceptions & Status Codes

If you have been following this FastAPI series, we have built CRUD operations, connected to a database, and secured our endpoints with JWTs. But what happens when things go wrong?

When a user searches for an item that doesn't exist, or tries to access a route without a token, your API needs to communicate the exact problem. Returning a generic 500 Internal Server Error or a standard 200 OK with an error message in the body is a bad practice.

Today, we are going to look at the most common HTTP status codes and how to raise them cleanly using FastAPI's HTTPException.

The Core Status Codes You Need to Know

HTTP status codes are grouped by their starting number.

  • 2xx (Success): Everything worked perfectly.

  • 4xx (Client Error): The user did something wrong (bad data, missing token, wrong URL).

  • 5xx (Server Error): Your code broke.

Image of 500 Server Error as code didn't work

Here are the four most critical 4xx errors you will use in FastAPI:

1. 404 Not Found

Use this when a requested resource does not exist in your database.

from fastapi import FastAPI, HTTPException

app = FastAPI()

fake_db = {"1": "Apple", "2": "Banana"}

@app.get("/items/{item_id}")
def get_item(item_id: str):
    if item_id not in fake_db:
        raise HTTPException(
            status_code=404, 
            detail=f"Item with ID {item_id} does not exist."
        )
    return {"item": fake_db[item_id]}
Enter fullscreen mode Exit fullscreen mode

Item not found

2. 400 Bad Request

Use this when the user sends invalid data. Note: If you use Pydantic models (like we covered in Part 4), FastAPI automatically handles 422 Validation Errors for you. But you can use 400 for custom business logic errors.


@app.post("/transfer")
def transfer_funds(amount: int):
    if amount <= 0:
        raise HTTPException(
            status_code=400, 
            detail="Transfer amount must be greater than zero."
        )
    return {"message": "Transfer successful"}
Enter fullscreen mode Exit fullscreen mode

This is 422 error, when we add integers where strings should be there.

422 error image

3. 401 Unauthorized (Authentication)

This is the error you throw when someone tries to access a protected route without a JWT token, or with an expired/invalid token. Think of this as: "I don't know who you are."

from fastapi import Header

@app.get("/profile")
def get_profile(authorization: str = Header(default=None)):
    if not authorization or not authorization.startswith("Bearer "):
        raise HTTPException(
            status_code=401, 
            detail="Missing or invalid authentication token",
            headers={"WWW-Authenticate": "Bearer"},
        )
    return {"user": "ZeroShotAnu"}
Enter fullscreen mode Exit fullscreen mode

Authentication Error

4. 403 Forbidden (Authorization)

This is often confused with 401. You use 403 Forbidden when you know who the user is (their token is valid), but they do not have the permission to do what they are trying to do. Think of this as: "I know who you are, but you aren't an Admin."


@app.delete("/users/{user_id}")
def delete_user(user_id: str, current_user_role: str = "guest"):
    # The user is logged in, but they are just a guest
    if current_user_role != "admin":
        raise HTTPException(
            status_code=403, 
            detail="You do not have permission to delete users."
        )
    return {"message": "User deleted"}
Enter fullscreen mode Exit fullscreen mode

Another example I tried here is, we already have this user existing and hence it is forbidden to create the same user again.

Creating a new student - that already exists

Error

Error Image

So when I create a real new student,

Actual new student image

it shows a success response:

Success response Image

Showing 403 VS 200

Why This Matters

Proper status codes make your API predictable. When a frontend developer (or an AI Agent) interacts with your API, they don't read the text in your detail message first; their code looks at the status_code to decide what to do next.

If they see a 401, they redirect the user to the login screen.

If they see a 404, they show a "Page Not Found" illustration.

The next post will be the last post in this series, we will learn about APIRouter and Background tasks. Hope you enjoyed this series.
Do ask any questions you have in the comments below.

Top comments (0)