Global exception middleware helps catch errors in one place. It stops your app from crashing and shows friendly error messages.
Global exception middleware in FastAPI
Start learning this pattern below
Jump into concepts and practice - no test required
from fastapi import FastAPI, Request from fastapi.responses import JSONResponse app = FastAPI() @app.middleware("http") async def global_exception_middleware(request: Request, call_next): try: response = await call_next(request) return response except Exception as e: return JSONResponse( status_code=500, content={"detail": "An error occurred.", "error": str(e)} )
The middleware function must be async and accept request and call_next.
Use call_next(request) to continue processing the request.
from fastapi import FastAPI, Request from fastapi.responses import JSONResponse app = FastAPI() @app.middleware("http") async def catch_all_exceptions(request: Request, call_next): try: response = await call_next(request) return response except Exception: return JSONResponse(status_code=500, content={"message": "Oops! Something went wrong."})
from fastapi import FastAPI, Request from fastapi.responses import JSONResponse app = FastAPI() @app.middleware("http") async def log_and_handle_errors(request: Request, call_next): try: response = await call_next(request) return response except Exception as e: print(f"Error: {e}") # Log error return JSONResponse(status_code=500, content={"error": "Internal server error"})
This FastAPI app has a global exception middleware that catches all errors. The /divide endpoint divides two numbers. If you divide by zero, the middleware catches the error and returns a friendly JSON message instead of crashing.
from fastapi import FastAPI, Request from fastapi.responses import JSONResponse app = FastAPI() @app.middleware("http") async def global_exception_middleware(request: Request, call_next): try: response = await call_next(request) return response except Exception as e: return JSONResponse( status_code=500, content={"detail": "An error occurred.", "error": str(e)} ) @app.get("/divide") async def divide(a: int, b: int): result = a / b # This can raise ZeroDivisionError return {"result": result}
Global exception middleware catches errors from all routes in one place.
It helps keep your code clean by avoiding repeated try-except blocks.
Always return a proper HTTP response to avoid hanging requests.
Global exception middleware catches and handles errors for the whole FastAPI app.
It improves user experience by sending clear error messages.
It helps developers log and debug errors easily.
Practice
Solution
Step 1: Understand middleware role
Middleware runs for every request and can intercept errors globally.Step 2: Identify purpose of global exception middleware
It catches errors from any part of the app and handles them centrally.Final Answer:
To catch and handle errors for the entire application in one place -> Option DQuick Check:
Global error handling = catch all errors [OK]
- Confusing middleware with caching or documentation
- Thinking it manages database connections
- Assuming it only handles specific routes
Solution
Step 1: Recall FastAPI middleware syntax
FastAPI usesadd_middlewaremethod to add middleware.Step 2: Match correct method name
Onlyadd_middlewareis valid; others are incorrect method names.Final Answer:
app.add_middleware(ExceptionMiddleware, handler=custom_handler) -> Option BQuick Check:
Use add_middleware() to add middleware [OK]
- Using incorrect method names like use_middleware or register_middleware
- Confusing middleware with route decorators
- Missing required parameters in add_middleware
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
app = FastAPI()
@app.middleware("http")
async def catch_exceptions_middleware(request: Request, call_next):
try:
response = await call_next(request)
return response
except ValueError as e:
return JSONResponse(status_code=400, content={"error": str(e)})
@app.get("/test")
async def test_route():
raise ValueError("Invalid input")Solution
Step 1: Analyze middleware error handling
The middleware catches ValueError and returns JSONResponse with status 400 and error message.Step 2: Check route behavior
The route raises ValueError("Invalid input"), triggering the middleware's except block.Final Answer:
{"error": "Invalid input"} with status 400 -> Option CQuick Check:
Middleware catches ValueError and returns JSON error [OK]
- Assuming default 500 error instead of custom JSON response
- Confusing status codes 422 and 400
- Ignoring middleware and expecting normal route error
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
app = FastAPI()
@app.middleware("http")
async def exception_middleware(request: Request, call_next):
try:
response = call_next(request)
return response
except Exception as e:
return JSONResponse(status_code=500, content={"error": "Server error"})Solution
Step 1: Check async call to call_next
call_next is an async function and must be awaited.Step 2: Identify missing await
Code calls call_next(request) without await, causing a coroutine object to be returned instead of response.Final Answer:
Missing await before call_next(request) -> Option AQuick Check:
Always await async call_next() in middleware [OK]
- Forgetting to await async call_next
- Thinking JSONResponse can't be returned in middleware
- Believing middleware shouldn't catch exceptions
Solution
Step 1: Understand middleware vs exception handler
Middleware wraps all requests and can catch exceptions globally; exception handlers are per-exception but not middleware.Step 2: Check for logging and JSON response in middleware
@app.middleware('http') async def global_exception(request, call_next): try: return await call_next(request) except Exception as e: print(f"Error: {e}") return JSONResponse(status_code=500, content={"error": "Internal server error"}) uses @app.middleware('http') with try-except, logs error with print, and returns JSONResponse with status 500.Step 3: Verify other options
app.add_middleware(ExceptionMiddleware, handler=lambda req, exc: JSONResponse({"error": str(exc)}, status_code=500)) uses add_middleware incorrectly; C and D are exception handlers, not middleware.Final Answer:
@app.middleware('http') async def global_exception(request, call_next): try: return await call_next(request) except Exception as e: print(f"Error: {e}") return JSONResponse(status_code=500, content={"error": "Internal server error"}) -> Option AQuick Check:
Middleware with try-except and logging = @app.middleware('http') async def global_exception(request, call_next): try: return await call_next(request) except Exception as e: print(f"Error: {e}") return JSONResponse(status_code=500, content={"error": "Internal server error"}) [OK]
- Confusing middleware with exception handlers
- Using add_middleware incorrectly for exceptions
- Not logging exceptions inside middleware
