Debug FastAPI in VS Code: Breakpoints, Async, and 422s
Attach the VS Code debugger to FastAPI with one launch.json block, then step through async routes and dependency injection. Eight steps, plus a quick reference for the errors FastAPI raises most.
Why FastAPI Debugging Is Different
FastAPI runs on ASGI (async I/O). That means two things for debugging: errors happen in async context, and standard print-debugging often misses the timing of when things fail. A validation error before your function runs looks identical in the terminal to a runtime error inside your function, until you know where to look.
This guide covers the full debugging workflow: reading FastAPI's built-in error output, setting up VS Code breakpoints for async code, and using AI tools for cross-file root cause analysis.
Step 1: Read the Terminal Output First
When FastAPI starts with uvicorn app.main:app --reload, every request and every error prints to the terminal. Do not jump to the code before reading it.
A 422 validation error looks like:
A 500 server error looks like:
The status code tells you where the error originated:
| Status | Origin | Where to look |
|---|---|---|
| 422 | Pydantic validation | Request body vs model definition |
| 401/403 | Auth middleware | Dependency functions, token validation |
| 500 | Your route function | Traceback in terminal |
| 502/504 | Upstream service | External API calls, DB connection |
Step 2: Use /docs for Request Validation
FastAPI auto-generates interactive docs at http://localhost:8000/docs. Before writing any debug code, test your endpoint directly in Swagger UI.
For 422 errors specifically, the /docs schema shows required vs optional fields, expected types, and field constraints. Compare your actual request against it directly.
Step 3: Add Structured Logging
print() works for simple cases. For async FastAPI, structured logging gives you context you cannot get from print:
structlog adds key-value pairs to every log line. When you search the logs for a specific user or order, you see the full sequence of events, not just where it crashed.
Step 4: Set Up VS Code Debugger for FastAPI
VS Code's Python debugger works with FastAPI but needs a launch configuration that handles uvicorn correctly.
Create .vscode/launch.json in your project root:
"module": "uvicorn" not "program": "uvicorn". The module form handles Python path resolution correctly across virtual environments and makes breakpoints in your code work reliably.
Set a breakpoint by clicking the gutter to the left of a line number inside any route function. Press F5 to start debugging. Send a request and execution pauses at your breakpoint so you can inspect all variables.
Step 5: Debug Async Functions
Await points are common places for bugs. The awaited coroutine can raise, return None, or hang. Set breakpoints on the await line to inspect what happens:
When the debugger pauses at that line, F10 (step over) executes the await and moves to the next line. The user variable in the debug panel shows what db.find_user() actually returned, including None if the record does not exist.
asyncio.gather() calls. The debugger can lose track of coroutine context in those cases. Wrap the suspicious code in a regular async function and debug that instead.
Step 6: Debug Dependencies
FastAPI's dependency injection runs before your route function. Bugs in dependencies show stack traces that point into FastAPI internals, not your code, which is confusing.
Set a breakpoint inside the dependency function itself. When a request hits an endpoint that uses this dependency, the debugger pauses in the dependency and lets you inspect the token, payload, and user_id before the route function runs.
Step 7: Reproduce Production Errors Locally
Production FastAPI errors often include a traceback in your logs. To reproduce:
- Copy the exact request body from your logs
- Paste it into
/docs, click "Try it out", and send - If it fails locally, you have reproduced it
For errors that only happen with specific database state, add a temporary debug endpoint:
include_in_schema=False hides it from Swagger. Gives you a debugging endpoint without polluting your API surface.
Step 8: Use AI for Cross-File Errors
FastAPI apps span multiple files: routes, services, models, dependencies, database layer. When a traceback points deep into your service layer, the root cause is often 3 to 4 files away from where the error surfaces.
AttributeError: 'NoneType' object has no attribute 'stripe_customer_id' in billing_service.py line 47
Manual approach: read the traceback, find what called billing_service, find what passed the user object, find where user was loaded, find where it might return None.
DebugAI approach: highlight the error and click Debug with AI. It reads the traceback, loads billing_service.py, loads the caller, loads the user model and query, and tells you that get_user() in users.py returns None for users who registered before the stripe_customer_id column was added and the schema migration was not backfilled.
Cross-file bugs in async services are the fastest DebugAI use case. The dependency chain is too long to trace manually in a reasonable time.
Common FastAPI Errors Quick Reference
| Error | Likely cause | First thing to check |
|---|---|---|
| 422 Unprocessable Entity | Pydantic validation fail | detail array in response body |
| 500 Internal Server Error | Exception in route or dependency | Terminal traceback |
| 401 Unauthorized | Auth dependency failed | JWT decode, token expiry |
| 404 Not Found | Wrong route or HTTPException(404) | Route path, HTTP method |
| RuntimeError: no running event loop | Sync code calling async | Ensure await on async functions |
| greenlet_spawn has not been called | SQLAlchemy async session misuse | Use AsyncSession, not Session |
FastAPI with the VS Code debugger covers 90% of bugs. For the rest, cross-service async timing issues and production-only database state bugs, paste the error and relevant files into DebugAI and it will trace the full dependency chain without hours of log-reading.
Debug faster starting today.
Free VS Code extension · 10 sessions/day · no credit card