feat(remix): Complete Remix 3 server error handling - #24878
Conversation
|
bugbot run |
6636642 to
d5cfe2f
Compare
size-limit report 📦
|
d5cfe2f to
57ee22d
Compare
513745c to
9fa7790
Compare
9fa7790 to
7083500
Compare
7083500 to
c199a22
Compare
|
bugbot run |
1 similar comment
|
bugbot run |
c199a22 to
3acd8b2
Compare
|
bugbot run |
3acd8b2 to
efcec61
Compare
|
bugbot run |
Covers the error paths the router middleware alone does not see, and stops reporting things that are not faults. `createRequestListener` in `@remix-run/node-fetch-server` is patched to install an `onError` that chains to the app's own. This is the only hook that covers an app whose fetch handler is not a router. It needs no abort guard: the listener checks `isRequestAbortError` itself and returns before calling `onError`. The middleware captures too, so an event carries the route and request already on the scope. That path does need the abort guard, because `raceRequestAbort` rejects with `signal.reason` when the client disconnects. Without it every user navigating away mid request creates an issue. Removing the guard makes the new e2e test fail. `shouldHandleError` follows `@sentry/hono`: skip 3xx and 4xx errors carrying a numeric `status`, capture the rest. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
efcec61 to
5ad3a52
Compare
| captureRequestError(error, context.request, 'auto.http.remix_v3.middleware'); | ||
| throw error; | ||
| } | ||
|
|
||
| setResponseStatus(response); |
There was a problem hiding this comment.
Bug: Primitive values thrown from Remix route handlers are reported twice because the de-duplication logic only works for Error objects, causing both the middleware and onError handler to capture the error.
Severity: LOW
Suggested Fix
The error handling logic should be updated to prevent double reporting for all thrown types. One possible solution is to wrap any captured primitive in an Error object at the earliest capture point. This would allow the existing de-duplication mechanism, which marks objects to prevent re-capture, to function correctly for all thrown values and ensure they are only reported to Sentry once.
Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.
Location: packages/remix/src/v3/server/middleware.ts#L38-L42
Potential issue: Primitive values, such as strings or numbers, thrown from Remix route
handlers can be captured and reported to Sentry twice. This occurs because the
de-duplication mechanism, which relies on marking an error as caught, does not work for
primitives. As a result, a thrown primitive is first captured by the router middleware
and then again by the `onError` handler. This leads to two separate Sentry events for
the same underlying error, creating noise and potentially confusing error tracking data.
While this is an acknowledged limitation in a code comment, it remains an issue that
will affect applications that throw primitives in their handlers.
Also affects:
packages/remix/src/v3/server/instrument.ts:96~100
Did we get this right? 👍 / 👎 to inform future reviews.
| options.onError = error => { | ||
| captureRequestError(error, undefined, 'auto.http.remix_v3.on_error'); | ||
|
|
||
| // Chained so the app keeps its own response. | ||
| return appOnError?.(error); | ||
| }; |
There was a problem hiding this comment.
When overwriting the error handler, we would remove their default error handling, no?
Maybe we can test that that the error is still logged to the console (like in their default error handler).
Setting `onError` replaces the listener's default handler, which logs the error to the console. When the app passed no handler of its own, the hook now logs the same way after capturing. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
|
bugbot run |
|
bugbot run |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit ad5bcdb. Configure here.
Covers the error paths the router middleware alone does not see, and stops reporting things that are not faults.
createRequestListenerin@remix-run/node-fetch-serveris patched to install anonErrorthat chains to the app's own. This is the only hook that covers an app whose fetch handler is not a router. It needs no abort guard: the listener checksisRequestAbortErroritself and returns before callingonError.The middleware captures too, so an event carries the route and request already on the scope. That path does need the abort guard, because
raceRequestAbortrejects withsignal.reasonwhen the client disconnects. Without it every user navigating away mid request creates an issue. Removing the guard makes the new e2e test fail.shouldHandleErrorfollows@sentry/hono: skip 3xx and 4xx errors carrying a numericstatus, capture the rest.Fixes #24664