Summary
The catch-all exception handler captures exc and discards it:
@app.exception_handler(Exception)
async def unhandled(_req, exc: Exception):
return JSONResponse(status_code=500, content={"error": {"message": "Internal server error", ...}})
No traceback, no type, no request path — every production 500 is completely undebuggable. The auth middleware does the same thing (app/middleware/auth.py:97-99), converting any DB failure during key validation into a bare 503 with nothing recorded.
These are the highest-leverage observability gaps in the repo: they sit above every other failure mode (including several swallowed-exception sites elsewhere), so until they log, none of those underlying incidents can be diagnosed from production output.
Proposed fix
- Extract the handler to a module-level
unhandled_exception_handler (so it's directly unit-testable) and call structlog.get_logger().exception("unhandled_exception", path=...) before returning the same 500 body.
- In
AuthMiddleware.__call__'s generic except Exception, log the exception (auth_middleware_error, with path) before sending the 503. Behavior/status codes unchanged.
Acceptance criteria
Summary
The catch-all exception handler captures
excand discards it:No traceback, no type, no request path — every production 500 is completely undebuggable. The auth middleware does the same thing (
app/middleware/auth.py:97-99), converting any DB failure during key validation into a bare 503 with nothing recorded.These are the highest-leverage observability gaps in the repo: they sit above every other failure mode (including several swallowed-exception sites elsewhere), so until they log, none of those underlying incidents can be diagnosed from production output.
Proposed fix
unhandled_exception_handler(so it's directly unit-testable) and callstructlog.get_logger().exception("unhandled_exception", path=...)before returning the same 500 body.AuthMiddleware.__call__'s genericexcept Exception, log the exception (auth_middleware_error, with path) before sending the 503. Behavior/status codes unchanged.Acceptance criteria