Day 10 · ~12m

Error Handling

Use HTTPException, custom error responses, and handle validation errors gracefully.

🧑‍💻

In Phase 1 we returned data, but what happens when something goes wrong? Like requesting a task that doesn't exist?

👩‍🏫

You raise an HTTPException. It's FastAPI's way of returning an error response with the right status code and a clear message:

from fastapi import FastAPI, HTTPException

app = FastAPI()
tasks = {1: {"id": 1, "title": "Demo"}}

@app.get("/tasks/{task_id}")
def get_task(task_id: int):
    if task_id not in tasks:
        raise HTTPException(status_code=404, detail="Task not found")
    return tasks[task_id]

When you raise HTTPException(status_code=404, detail="Task not found"), FastAPI stops executing the function and returns {"detail": "Task not found"} with HTTP status 404. The client gets a clear, structured error.

🧑‍💻

What status codes should I use for different errors?

👩‍🏫

Here are the ones you'll use constantly:

# Resource not found
raise HTTPException(status_code=404, detail="Task not found")

# Bad request — client sent invalid data
raise HTTPException(status_code=400, detail="Title cannot be empty")

# Unauthorized — no credentials
raise HTTPException(status_code=401, detail="Not authenticated")

# Forbidden — wrong permissions
raise HTTPException(status_code=403, detail="Not allowed to edit this task")

# Conflict — duplicate or state problem
raise HTTPException(status_code=409, detail="Task already exists")

The pattern: 4xx means the client did something wrong. 5xx means the server broke. Use the most specific code that applies.

🧑‍💻

What about Pydantic validation errors? Those 422 responses?

👩‍🏫

FastAPI handles those automatically. When a request body doesn't match the Pydantic model, you get a detailed 422 response. But you can add custom validation too:

from pydantic import BaseModel, field_validator

class TaskCreate(BaseModel):
    title: str
    priority: int

    @field_validator("priority")
    @classmethod
    def check_priority(cls, v):
        if v < 1 or v > 5:
            raise ValueError("Priority must be between 1 and 5")
        return v

Now sending {"title": "Test", "priority": 10} returns a 422 with your custom error message.

🧑‍💻

Can I return extra information in the error response?

👩‍🏫

The detail field can be a string, dict, or list — whatever helps the client understand what went wrong:

raise HTTPException(
    status_code=400,
    detail={
        "error": "validation_failed",
        "fields": ["title", "priority"],
        "message": "Multiple fields are invalid"
    }
)

Good error responses are as important as good success responses. A vague "Something went wrong" helps nobody. A specific {"detail": "Task 42 not found"} tells the client exactly what to fix.

Practice your skills

Sign up to write and run code in this lesson.

Already have an account? Sign in