-
Notifications
You must be signed in to change notification settings - Fork 166
Description
Question
FastAPI exception handlers: properly handled domain exceptions logged as errors in Logfire
Summary
When using Logfire's instrument_fastapi()
, exceptions that are properly handled by FastAPI exception handlers are still logged as errors in Logfire, even though they result in valid HTTP responses (404, 403, etc.). This pollutes error logs with normal business logic cases.
Expected Behavior
Exceptions that are handled by FastAPI exception handlers and converted to proper HTTP responses (4xx status codes) should NOT be logged as errors in Logfire. They should either not be logged as exceptions at all
Actual Behavior
All exceptions are logged as errors in Logfire, regardless of whether they're handled by exception handlers.
Code Example
Exception Handler Setup:
from fastapi import FastAPI
from fastapi.responses import JSONResponse
from generic_rag.domain.exceptions.base import DomainError
@app.exception_handler(DomainError)
async def domain_error_handler(request: Request, exc: DomainError) -> Response:
return JSONResponse(status_code=404, content={"detail": str(exc)})
# Logfire instrumentation
logfire.instrument_fastapi(app, capture_headers=True)
Route that raises handled exception:
@router.get("/users/{user_id}")
def get_user(user_id: UUID) -> User:
# This raises UserNotFoundError which inherits from DomainError
return domain.get_user_for_company(user_id, api_user)
Result in Logfire
{
"is_exception": true,
"exception_type": "generic_rag.domain.exceptions.users.UserNotFoundError",
"otel_status_code": "ERROR",
"http_response_status_code": 404
}

The HTTP response is correctly 404, but Logfire still logs it as an error.
Workaround
Currently, the only workaround is to wrap every route in try/catch, which contradicts the use of error handler:
@router.get("/users/{user_id}")
def get_user(user_id: UUID) -> User:
try:
return domain.get_user_for_company(user_id, api_user)
except DomainError as exc:
# Handle manually to avoid Logfire logging as error
return JSONResponse(status_code=404, content={"detail": str(exc)})
With this approach:
{
"is_exception": false,
"otel_status_code": "UNSET",
"http_response_status_code": 404
}

Questions
Am I missing something obvious here? I've searched through the documentation and tried different approaches, but couldn't find a clean solution that preserves the benefits of FastAPI's exception handler pattern while avoiding the error log pollution.
Environment
>>> import logfire; print(logfire.logfire_info())
logfire="4.3.3"
python="3.11.9 (main, Aug 14 2024, 05:07:28) [Clang 18.1.8 ]"
[related_packages]
requests="2.32.4"
pydantic="2.11.7"
fastapi="0.104.1"
openai="1.97.2"
protobuf="5.29.5"
rich="14.0.0"
executing="2.2.0"
opentelemetry-api="1.36.0"
opentelemetry-exporter-otlp="1.36.0"
opentelemetry-exporter-otlp-proto-common="1.36.0"
opentelemetry-exporter-otlp-proto-grpc="1.36.0"
opentelemetry-exporter-otlp-proto-http="1.36.0"
opentelemetry-instrumentation="0.57b0"
opentelemetry-instrumentation-asgi="0.57b0"
opentelemetry-instrumentation-celery="0.57b0"
opentelemetry-instrumentation-fastapi="0.57b0"
opentelemetry-instrumentation-llamaindex="0.45.6"
opentelemetry-instrumentation-sqlalchemy="0.57b0"
opentelemetry-proto="1.36.0"
opentelemetry-sdk="1.36.0"
opentelemetry-semantic-conventions="0.57b0"
opentelemetry-semantic-conventions-ai="0.4.12"
opentelemetry-util-http="0.57b0"
Sorry for the images that don't exactly match the snippets.