ModelEngine-Group / ModelEngine-Group/nexent
Two parallel exception-handling stacks emit incompatible error response shapes
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 5.9k
- Forks
- 731
- Avg merge
- 19h 34m
- Merged PRs (30d)
- 172
Description
The repo registers FastAPI error handlers in two different places, and they don't agree on the response schema.
Path A — backend/middleware/exception_handler.py:38 — installed as a BaseHTTPMiddleware:
return JSONResponse(
status_code=http_status,
content={
"code": exc.error_code.value,
"message": exc.message,
"trace_id": trace_id,
"details": exc.details if exc.details else None
}
)
…and for plain HTTPException:
content={"code": error_code.value, "message": exc.detail, "trace_id": trace_id}
Path B — backend/apps/app_factory.py:78-108 — registered via @app.exception_handler(...):
@app.exception_handler(HTTPException)
async def http_exception_handler(request, exc):
return JSONResponse(
status_code=exc.status_code,
content={"message": exc.detail}, # no code, no trace_id
)
@app.exception_handler(Exception)
async def generic_exception_handler(request, exc):
return JSONResponse(
status_code=500,
content={"message": "Internal server error, please try again later."}, # no code, no trace_id, generic message
)
Why it matters
- Frontend
services/api.ts(and the various typed services that wrapfetchWithErrorHandling) can't rely oncodeortrace_idbeing present — they sometimes are, sometimes aren't, depending on which handler intercepted the exception. FastAPI's@app.exception_handlerruns beforeBaseHTTPMiddlewarefor handled exceptions raised in route code, but middleware will still catch unhandled errors and wrap them with the richer schema — so the same logical error can return two different shapes depending on where it originated. - The middleware advertises a
trace_idin every response. Operators using it as a correlation key will find that some 4xx and 5xx responses lack it entirely.
Suggested fix
Pick one. Either:
- Remove
register_exception_handlersfromapp_factory.pyand rely onExceptionHandlerMiddlewareend-to-end, or - Update the
app_factory.pyhandlers to emit the same{code, message, trace_id, details}shape, sourcingtrace_idfromrequest.state.trace_id(which the middleware sets).
Also worth checking: app_factory.py:48-54 sets allow_origins=["*"] together with allow_credentials=True, which is non-compliant per CORS spec and silently ignored by browsers. Probably should be a separate issue but mentioning here for context.
Severity: Medium. Visible to API consumers; harms debuggability.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Read backend/middleware/exception_handler.py and backend/apps/app_factory.py first, comparing which exception paths produce each response shape and how request.state.trace_id is set. Verify the chosen approach makes HTTPException and generic errors consistently return code, message, trace_id, and details without changing the separate CORS concern.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- fastapi, python
- Domain
- api, backend
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 62/100