Claude
Skills
Sign in
Back

debug:fastapi

Included with Lifetime
$97 forever

Debug FastAPI applications systematically with this comprehensive troubleshooting skill. Covers async/await issues, Pydantic validation errors (422 responses), dependency injection failures, CORS configuration problems, database session management, and circular import resolution. Provides structured four-phase debugging methodology with FastAPI-specific tools including uvicorn logging, OpenAPI docs, and middleware debugging patterns.

Backend & APIs

What this skill does


# FastAPI Debugging Guide

## Overview

This skill provides a systematic approach to debugging FastAPI applications. FastAPI is built on Starlette and Pydantic, which means debugging often involves understanding async behavior, request validation, and dependency injection patterns.

**When to use this skill:**
- 422 Unprocessable Entity errors
- Pydantic ValidationError exceptions
- Async/await related issues
- Dependency injection failures
- CORS errors in browser
- 500 Internal Server Errors
- Database session/connection issues
- Circular import errors on startup

## Common Error Patterns

### 1. Pydantic ValidationError (422 Unprocessable Entity)

**Symptoms:**
- API returns 422 status code
- Response contains `detail` array with validation errors
- Client receives "field required" or "type error" messages

**Root Causes:**
- Missing required fields in request body
- Incorrect data types (string instead of int, etc.)
- Invalid enum values
- Nested model validation failures

**Debugging Steps:**
```python
# 1. Check the exact error response
{
    "detail": [
        {
            "loc": ["body", "field_name"],
            "msg": "field required",
            "type": "value_error.missing"
        }
    ]
}

# 2. Validate your Pydantic model directly
from pydantic import BaseModel, ValidationError

class UserCreate(BaseModel):
    name: str
    email: str
    age: int

try:
    user = UserCreate(**your_data)
except ValidationError as e:
    print(e.json())  # Detailed error info

# 3. Use Optional for non-required fields
from typing import Optional

class UserCreate(BaseModel):
    name: str
    email: str
    age: Optional[int] = None  # Now optional with default
```

### 2. 500 Internal Server Error

**Symptoms:**
- Generic "Internal Server Error" response
- No detailed error in API response
- Error details only in server logs

**Root Causes:**
- Unhandled exceptions in endpoint code
- Database connection failures
- Dependency injection failures
- Division by zero, null attribute access
- External service timeouts

**Debugging Steps:**
```python
# 1. Add exception logging middleware
import logging
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse

logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)

app = FastAPI()

@app.middleware("http")
async def log_exceptions(request: Request, call_next):
    try:
        return await call_next(request)
    except Exception as e:
        logger.exception(f"Unhandled exception: {e}")
        raise

# 2. Add global exception handler
@app.exception_handler(Exception)
async def global_exception_handler(request: Request, exc: Exception):
    logger.exception(f"Unhandled: {exc}")
    return JSONResponse(
        status_code=500,
        content={"detail": str(exc)}  # Only in dev!
    )

# 3. Check dependency injection
from fastapi import Depends

def get_db():
    db = SessionLocal()
    try:
        yield db
    except Exception as e:
        logger.error(f"DB error: {e}")
        raise
    finally:
        db.close()
```

### 3. Async/Await Issues

**Symptoms:**
- `RuntimeError: Event loop is already running`
- `RuntimeWarning: coroutine was never awaited`
- Blocking behavior in async endpoints
- `TypeError: object X can't be used in 'await' expression`

**Root Causes:**
- Mixing sync and async code incorrectly
- Using blocking I/O in async functions
- Missing await keywords
- Sync database calls in async context

**Debugging Steps:**
```python
# 1. Check for missing await
# Wrong
@app.get("/users")
async def get_users():
    users = db.get_users()  # If async, needs await!
    return users

# Correct
@app.get("/users")
async def get_users():
    users = await db.get_users()
    return users

# 2. Don't use blocking I/O in async functions
# Wrong - blocks event loop
@app.get("/data")
async def get_data():
    import time
    time.sleep(5)  # BLOCKS!
    return {"data": "done"}

# Correct - use asyncio.sleep or run_in_executor
import asyncio
@app.get("/data")
async def get_data():
    await asyncio.sleep(5)  # Non-blocking
    return {"data": "done"}

# 3. For sync database operations, use def instead of async def
@app.get("/users")
def get_users(db: Session = Depends(get_db)):
    # FastAPI runs sync functions in threadpool
    return db.query(User).all()
```

### 4. Dependency Injection Errors

**Symptoms:**
- `TypeError: X() takes Y positional arguments but Z were given`
- Dependencies not being called
- `ValidationError` from dependency parameters

**Debugging Steps:**
```python
# 1. Ensure Depends() is used correctly
from fastapi import Depends

# Wrong - function is called immediately
@app.get("/items")
def get_items(db = get_db()):  # WRONG!
    pass

# Correct - FastAPI manages the dependency
@app.get("/items")
def get_items(db = Depends(get_db)):
    pass

# 2. Debug dependency chain
def get_settings():
    print("Loading settings...")  # Debug print
    return Settings()

def get_db(settings: Settings = Depends(get_settings)):
    print(f"Connecting to {settings.db_url}")  # Debug print
    return create_engine(settings.db_url)

# 3. Handle dependency failures gracefully
async def get_current_user(token: str = Depends(oauth2_scheme)):
    try:
        user = await verify_token(token)
        if not user:
            raise HTTPException(status_code=401, detail="Invalid token")
        return user
    except Exception as e:
        logger.error(f"Auth failed: {e}")
        raise HTTPException(status_code=401, detail="Authentication failed")
```

### 5. CORS Problems

**Symptoms:**
- Browser console shows CORS errors
- API works in Postman but not browser
- Preflight OPTIONS requests failing

**Debugging Steps:**
```python
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

app = FastAPI()

# 1. Add CORS middleware (MUST be before routes)
app.add_middleware(
    CORSMiddleware,
    allow_origins=["http://localhost:3000"],  # Or ["*"] for dev
    allow_credentials=True,
    allow_methods=["*"],
    allow_headers=["*"],
)

# 2. Debug: Log all requests
@app.middleware("http")
async def log_requests(request, call_next):
    print(f"Origin: {request.headers.get('origin')}")
    print(f"Method: {request.method}")
    response = await call_next(request)
    print(f"CORS headers: {dict(response.headers)}")
    return response

# 3. Common issues:
# - allow_origins must match EXACTLY (including protocol and port)
# - allow_credentials=True requires specific origins (not "*")
# - Check if middleware order is correct
```

### 6. Database Session Issues

**Symptoms:**
- `sqlalchemy.exc.InvalidRequestError: This Session's transaction has been rolled back`
- Database connections exhausted
- Stale data being returned

**Debugging Steps:**
```python
from sqlalchemy.orm import Session
from contextlib import contextmanager

# 1. Proper session management
def get_db():
    db = SessionLocal()
    try:
        yield db
        db.commit()  # Commit on success
    except Exception:
        db.rollback()  # Rollback on error
        raise
    finally:
        db.close()  # Always close

# 2. Check connection pool settings
from sqlalchemy import create_engine

engine = create_engine(
    DATABASE_URL,
    pool_size=5,
    max_overflow=10,
    pool_timeout=30,
    pool_pre_ping=True,  # Test connections before use
    echo=True,  # Log all SQL (debug only!)
)

# 3. Debug session state
@app.get("/debug-db")
def debug_db(db: Session = Depends(get_db)):
    print(f"Session active: {db.is_active}")
    print(f"Session dirty: {db.dirty}")
    print(f"Session new: {db.new}")
    return {"status": "ok"}
```

### 7. Circular Import Errors

**Symptoms:**
- `ImportError: cannot import name 'X' from partially initialized module`
- Application fails to start
- `AttributeError: module has no attribute`

**Debugging Steps:**
```python
# 1. Identify the circular dependency
# app/models.py
from app.schemas import UserSchema  # Imports schemas

# app/schemas.py

Related in Backend & APIs