FastAPI's async-first design makes it great for high-throughput APIs, but exceptions in async handlers can be silent. A rejected coroutine here, an unhandled background task there, and your users see 500s while your logs stay quiet. You might not find out about it until a user emails support or leaves a negative review. FastAPI error tracking with the Sentry SDK turns those invisible failures into grouped issues in a dashboard, so you catch bugs before they cascade and fix them before they become incidents.
This guide sets up production-grade error tracking in a FastAPI app using the Sentry SDK, pointed at LightTrace. By the end you'll capture async exceptions, attach request context, trace slow endpoints, and know exactly what broke and why. The whole setup takes about 10 minutes and requires only a few configuration changes.
Install and initialize the SDK
Add the Sentry SDK for Python and initialize it before your app starts. Because LightTrace speaks the Sentry protocol, you use the standard sentry-sdk package and change only the dsn. LightTrace is compatible with the Sentry SDK across all languages, so switching from Sentry requires only changing the DSN endpoint.
pip install sentry-sdk
# main.py
import sentry_sdk
from fastapi import FastAPI
from sentry_sdk.integrations.fastapi import FastApiIntegration
from sentry_sdk.integrations.starlette import StarletteIntegration
sentry_sdk.init(
dsn="https://<key>@your-lighttrace-host/1",
integrations=[
FastApiIntegration(),
StarletteIntegration(),
],
environment="production",
release="api@1.2.3",
traces_sample_rate=1.0,
)
app = FastAPI()
@app.get("/health")
async def health():
return {"status": "ok"}
That single init call does three things: it installs global exception handlers for uncaught exceptions and unhandled rejections, it activates the FastAPI and Starlette integrations to capture request data automatically, and it configures the connection to LightTrace. From this point forward, any unhandled error in your async handlers or middleware is captured and sent to your dashboard. The FastAPI integration hooks into the request/response cycle, so every error arrives with context: the HTTP method, path, query params, headers, body, and response status.
Set traces_sample_rate=1.0 to capture 100% of transactions for complete visibility into slow endpoints. For high-traffic APIs, lower it to 0.1 or 0.01 to control data volume once you're confident in your setup.
Capture async exceptions and background tasks
FastAPI's async model means exceptions can hide in tasks that fire and forget. A background job that fails silently won't surface in your logs or request traces. The SDK handles exceptions in request handlers automatically, but background tasks need explicit error handling if they're not part of the request lifecycle.
from fastapi import BackgroundTasks
from datetime import datetime
@app.post("/send-email")
async def send_email(email: str, background_tasks: BackgroundTasks):
# This runs in the request cycle and is captured automatically
if not email:
raise ValueError("Email required")
# This runs in the background and needs explicit error handling
async def notify_user():
try:
await send_notification(email)
except Exception as exc:
# Explicitly capture so it shows up in LightTrace
sentry_sdk.capture_exception(exc)
background_tasks.add_task(notify_user)
return {"status": "email queued"}
You can also set up global exception handlers for any uncaught async exceptions. This ensures that even exceptions from background tasks, scheduled jobs, or fire-and-forget operations reach LightTrace:
import asyncio
from typing import Coroutine
def handle_exception(loop, context):
"""Global handler for async exceptions"""
exc = context.get("exception")
if exc:
sentry_sdk.capture_exception(exc)
else:
sentry_sdk.capture_message(context.get("message", "Unknown error"))
asyncio.get_event_loop().set_exception_handler(handle_exception)
For Celery or other async job systems, the Sentry SDK has dedicated integrations. Check the Python error tracking guide for a deeper look at integrating task queues.
Attach request context for faster debugging
Raw errors tell you what broke. Context tells you why and who. Set the user and add breadcrumbs at key moments so every error arrives with the path that led to it. Without context, you get a stack trace; with it, you get a story.
from fastapi import Request
@app.middleware("http")
async def set_user_context(request: Request, call_next):
# Extract user from JWT or session
user_id = request.headers.get("X-User-ID")
if user_id:
sentry_sdk.set_user({"id": user_id})
# Add request path as breadcrumb
sentry_sdk.add_breadcrumb(
category="request",
message=f"{request.method} {request.url.path}",
level="info",
)
response = await call_next(request)
return response
You can also add custom breadcrumbs for important operations within a request:
sentry_sdk.add_breadcrumb(
category="payment",
message="Payment processing started",
level="info",
data={"amount": 29.99, "currency": "USD"}
)
Now every error in LightTrace arrives tagged with the user ID, the request method and path, and a complete trail of breadcrumbs showing what happened before the crash. That context cuts the time to reproduce from hours to minutes — instead of guessing what the user did, you see the exact sequence of operations that led to the error.
Breadcrumbs are the context stack traces miss. They record the events leading up to a crash — HTTP requests, database queries, cache hits — so you can reproduce the exact path that broke your API.
Monitor slow endpoints with distributed tracing
An endpoint that's fast on average can be slow for 5% of users — and those are the requests that matter most. A response time that looks fine at P50 (median) might be brutal at P99 (the slowest 1% of requests). The Sentry SDK captures transaction traces automatically, so you see not just slow endpoints but where the time went.
@app.get("/users/{user_id}")
async def get_user(user_id: int):
# This entire endpoint is automatically wrapped in a transaction
# The SDK captures the span timing and any child spans
user = await fetch_user(user_id)
posts = await fetch_posts(user_id) # This is a separate span
return {"user": user, "posts": posts}
When you deploy with tracing enabled, LightTrace captures the P50, P75, P95, and P99 latency for every endpoint. Notice an endpoint spiking? Click into it and see a span waterfall showing exactly where the time went — a slow database query, a timeout waiting for an external API, a missing index, or an N+1 problem iterating over rows.
The SDK automatically instruments common operations like HTTP requests and database queries, but you can also add custom spans for any operation you care about:
with sentry_sdk.start_span(op="custom.operation", description="Processing large file") as span:
result = await process_large_file(file_path)
span.set_data("file_size", len(result))
For deeper debugging, read about span waterfalls and how to use distributed tracing to correlate failures across services.
Mask sensitive data before it leaves
Error payloads can leak API keys, passwords, and PII. The SDK has built-in rules to scrub common sensitive fields, and you can add custom rules.
import sentry_sdk
def scrub_before_send(event, hint):
# Redact Authorization headers
if "request" in event:
request = event["request"]
if "headers" in request and "authorization" in request["headers"]:
request["headers"]["authorization"] = "[REDACTED]"
return event
sentry_sdk.init(
dsn="https://<key>@your-lighttrace-host/1",
before_send=scrub_before_send,
)
LightTrace has data scrubbing built in, and the SDK's before-send hook gives you fine-grained control over what reaches the server. Never send passwords, tokens, or PII — filter them out before they leave your app.
Deploy and start catching errors
With the SDK initialized and integrations in place, deploy and watch the first errors arrive. LightTrace groups them automatically using fingerprinting, so identical exceptions collapse into a single issue with a count instead of flooding you with noise. Ten thousand instances of the same bug becomes one line in your issue list.
The SDK captures and sends errors asynchronously, so it won't slow down your requests. By default it uses a background thread to batch events and send them in bulk, but you can tune this if you have strict latency requirements.
Once you're seeing errors, set up alert rules so you're notified the moment a new issue appears or an existing one spikes. The error tracking best practices guide walks through the settings that cut false alarms and keep your team focused on real regressions.
Correlate errors with releases
Error tracking is most powerful when you know which release introduced a bug. Tag every event with a release so you can see error trends across deployments and quickly identify regressions:
sentry_sdk.init(
dsn="https://<key>@your-lighttrace-host/1",
environment="production",
release="api@1.2.3", # Tag errors with the release
traces_sample_rate=1.0,
)
When an error appears after a deploy, you can read how the issue changed across releases and often pinpoint the exact commit.
Start tracking errors in minutes
Point the Sentry SDK at LightTrace and see your first FastAPI errors grouped and ready to fix — free up to 5,000 events a month.
Error tracking isn't a luxury for mature teams. It's the difference between shipping an API and shipping one you trust. With async exceptions captured, request context attached, slow endpoints visible, and errors tied to releases, you ship faster and sleep better. Your FastAPI service deserves the same visibility as your frontend.