Skip to content

fix(observability): unhandled exceptions are swallowed with zero logging (500s and auth 503s undebuggable) #80

Description

@hasitpbhatt

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

  • A route raising an arbitrary exception still returns the identical 500 JSON envelope.
  • A structured-log event with the exception and request path is emitted for both the 500 handler and the middleware 503 branch.
  • Existing status-code contracts unchanged (401 auth errors are unaffected).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions