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.
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.