ADR 0010: CORS middleware wraps the error catcher¶
- Status:
Accepted
Context¶
Starlette’s default error middleware is outermost, so a real 500 ships
without CORS headers. A browser then drops the response and the dashboard
shows a bare “Network Error” with no status - hiding the actual backend fault.
Decision¶
A pure-ASGI CatchUnhandledErrorsMiddleware is registered first and
CORSMiddleware second (app/main.py). Because add_middleware
prepends, CORS ends up outermost and wraps the catcher. The catcher
converts an unhandled exception into a JSON 500 from inside the stack, so
the response flows back out through CORS and gets its Access-Control-Allow-*
headers; the traceback is still logged and sent to Sentry.
Consequences¶
Error responses keep their CORS headers, so the browser (and the dashboard) see the real
500instead of an opaque “Network Error”.The registration order is load-bearing and easy to break, so the why is documented next to the registration.
See also¶
Architecture - “The middleware stack (and a subtle ordering bug it fixes)”.
Troubleshooting - the “Network Error” symptom.