fix(errors): report an unhandled error as 500 rather than 404 - #239
Merged
Conversation
The first error handler answered the CORS rejection and passed everything else on with a bare next(). From an error handler that clears the error and resumes at the next regular middleware, so the 500 handler directly below was skipped and control landed on the 404. Every unhandled exception was reported to the caller as 404 Not Found. The 404 handler also logs a requestSuspicious event, so each internal error was written into the anomaly signal as suspicious behaviour by whoever sent the request. Routing errors to the 500 handler takes them out of that stream. A genuinely unmatched route still answers 404. Surveyed the dependents: the React SDK does not branch on 404 at all, the server adapter's only reference is an unrelated comment, and the admin dashboard already maps 5xx to a clearer message than the 404 text it was getting.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #230.
Calling
next()with no argument from an error-handling middleware clears the error and resumes at the next regular middleware. That skipped the 500 handler sitting directly below and landed on the 404, so every unhandled exception was reported to the caller as404 {"error":"Not Found"}.Why this mattered more than the status code
The 404 handler logs an
AuthEventService.requestSuspiciousevent with reason "Request to an unknown route." So each internal fault was written into the anomaly signal the dashboard and the security views read, attributed to whoever happened to send the request. Server bugs were polluting the stream meant for hostile callers, and doing it precisely when the server was misbehaving. There is now a test asserting a server error records nothing.The second consequence is that a 500 is alertable and a 404 on an auth API is background noise. This masked a genuine regression through a full test run during the Express 5 work.
Contract change and blast radius
A request that triggers an unhandled exception now answers
500 {"error":"Internal server error"}instead of404 {"error":"Not Found"}. A genuinely unmatched route still answers 404, unchanged. Callers that retry on 5xx but not 4xx will now retry these.Surveyed the dependents before committing:
src. Unaffected.404reference is a comment in the fastify console proxy about method handling. Unaffected.friendlyStatusMessagemapped these to "The requested resource was not found." and will now say "The Seamless Auth API had a problem. Try again shortly." ItsMESSAGE_SURFACING_STATUSESdeliberately excludes 5xx, and the 500 body is generic, so nothing upstream leaks.No coordinated release needed.
On the existing test
passes non-CORS errors through to the not-found handlerpinned the old 404, which is why I raised this as a question rather than assuming it was a bug. Replaced with one asserting the 500, plus one asserting the suspicious event is not recorded.Verification
Exactly one existing test moved, the one that pinned the behaviour. Full suite 1195 passed, 1 skipped.
minorchangeset per the pre-1.0 rule, describing the break in the body.