Skip to content

feat(remix): Complete Remix 3 server error handling - #24878

Merged
chargome merged 2 commits into
charlygomez/js-3770-integrate-with-the-remix-3-asset-server-for-debug-idsfrom
charlygomez/js-3767-complete-remix-3-server-error-handling
Oct 1, 2026
Merged

chargome merged 2 commits into
charlygomez/js-3770-integrate-with-the-remix-3-asset-server-for-debug-idsfrom
charlygomez/js-3767-complete-remix-3-server-error-handling

Conversation

@chargome

Copy link
Copy Markdown
Member

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.

Fixes #24664

@chargome chargome self-assigned this Sep 30, 2026
@linear-code

linear-code Bot commented Sep 30, 2026

Copy link
Copy Markdown

JS-3767

@chargome

Copy link
Copy Markdown
Member Author

bugbot run

@chargome
chargome force-pushed the charlygomez/js-3767-complete-remix-3-server-error-handling branch from 6636642 to d5cfe2f Compare September 30, 2026 10:29

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

@github-actions

github-actions Bot commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor

size-limit report 📦

Path Size % Change Change
@sentry/browser 29.51 kB - -
@sentry/browser - with treeshaking flags 27.68 kB - -
@sentry/browser - with treeshaking flags tracing without tracing 27.58 kB - -
@sentry/browser (incl. Tracing) 51.46 kB - -
@sentry/browser (incl. Tracing + Span Streaming) 51.47 kB - -
@sentry/browser (incl. Tracing, Profiling) 54.47 kB - -
@sentry/browser (incl. Tracing, Replay) 91.05 kB - -
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags 80.03 kB - -
@sentry/browser (incl. Tracing, Replay with Canvas) 95.73 kB - -
@sentry/browser (incl. Tracing, Replay, Feedback) 108.72 kB - -
@sentry/browser (incl. Feedback) 47.04 kB - -
@sentry/browser (incl. sendFeedback) 34.57 kB - -
@sentry/browser (incl. FeedbackAsync) 39.69 kB - -
@sentry/browser (incl. Metrics) 30.53 kB - -
@sentry/browser (incl. Logs) 30.82 kB - -
@sentry/browser (incl. Metrics & Logs) 31.48 kB - -
@sentry/react 31.36 kB - -
@sentry/react (incl. Tracing) 53.82 kB - -
@sentry/vue 37.51 kB - -
@sentry/vue (incl. Tracing) 54.36 kB - -
@sentry/svelte 29.54 kB - -
@sentry/remix (Remix 3 client bundle) 55.75 kB +0.52% +284 B 🔺
CDN Bundle 31.22 kB - -
CDN Bundle (incl. Tracing) 51.99 kB - -
CDN Bundle (incl. Logs, Metrics) 33.46 kB - -
CDN Bundle (incl. Tracing, Logs, Metrics) 53.94 kB - -
CDN Bundle (incl. Replay, Logs, Metrics) 74.2 kB - -
CDN Bundle (incl. Tracing, Replay) 89.56 kB - -
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) 91.54 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback) 95.73 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) 97.73 kB - -
CDN Bundle - uncompressed 92.14 kB - -
CDN Bundle (incl. Tracing) - uncompressed 154.53 kB - -
CDN Bundle (incl. Logs, Metrics) - uncompressed 98.71 kB - -
CDN Bundle (incl. Tracing, Logs, Metrics) - uncompressed 160.48 kB - -
CDN Bundle (incl. Replay, Logs, Metrics) - uncompressed 228.28 kB - -
CDN Bundle (incl. Tracing, Replay) - uncompressed 274.26 kB - -
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed 280.2 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed 287.96 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed 293.89 kB - -
@sentry/nextjs (client) 56.33 kB - -
@sentry/sveltekit (client) 51.88 kB - -
@sentry/core/server 39.99 kB - -
@sentry/core/browser 13.63 kB - -
@sentry/node 144.4 kB +0.06% +82 B 🔺
@sentry/node/import (ESM hook with diagnostics-channel injection) 83.08 kB +0.08% +64 B 🔺
@sentry/node - without tracing 93.03 kB +0.09% +83 B 🔺
@sentry/node - without channel injection 122.66 kB +0.01% +12 B 🔺
@sentry/aws-serverless 101.33 kB +0.09% +83 B 🔺
@sentry/cloudflare (withSentry) - minified 206.83 kB - -
@sentry/cloudflare (withSentry) 514.6 kB - -

View base workflow run

@chargome
chargome added this pull request to stack #24884 September 30, 2026 11:41
@chargome
chargome force-pushed the charlygomez/js-3767-complete-remix-3-server-error-handling branch from d5cfe2f to 57ee22d Compare September 30, 2026 13:41
@chargome
chargome force-pushed the charlygomez/js-3767-complete-remix-3-server-error-handling branch 3 times, most recently from 513745c to 9fa7790 Compare September 30, 2026 14:43
@chargome
chargome force-pushed the charlygomez/js-3767-complete-remix-3-server-error-handling branch from 9fa7790 to 7083500 Compare September 30, 2026 15:01
@chargome
chargome force-pushed the charlygomez/js-3767-complete-remix-3-server-error-handling branch from 7083500 to c199a22 Compare October 1, 2026 08:12
@chargome

chargome commented Oct 1, 2026

Copy link
Copy Markdown
Member Author

bugbot run

1 similar comment
@chargome

chargome commented Oct 1, 2026

Copy link
Copy Markdown
Member Author

bugbot run

@chargome
chargome force-pushed the charlygomez/js-3767-complete-remix-3-server-error-handling branch from c199a22 to 3acd8b2 Compare October 1, 2026 08:21
@chargome

chargome commented Oct 1, 2026

Copy link
Copy Markdown
Member Author

bugbot run

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

Comment thread packages/remix/src/v3/server/instrument.ts
@chargome
chargome force-pushed the charlygomez/js-3767-complete-remix-3-server-error-handling branch from 3acd8b2 to efcec61 Compare October 1, 2026 08:32
@chargome

chargome commented Oct 1, 2026

Copy link
Copy Markdown
Member Author

bugbot run

@chargome
chargome marked this pull request as ready for review October 1, 2026 08:38
@chargome
chargome requested review from a team as code owners October 1, 2026 08:38
@chargome
chargome requested review from nicohrubec and s1gr1d and removed request for a team October 1, 2026 08:38
@chargome
chargome requested review from isaacs and mydea and removed request for a team October 1, 2026 08:38

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous 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>
@chargome
chargome force-pushed the charlygomez/js-3767-complete-remix-3-server-error-handling branch from efcec61 to 5ad3a52 Compare October 1, 2026 13:33
Comment on lines +38 to 42
captureRequestError(error, context.request, 'auto.http.remix_v3.middleware');
throw error;
}

setResponseStatus(response);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Comment thread packages/remix/src/v3/server/errorFilter.ts
Comment on lines +92 to +97
options.onError = error => {
captureRequestError(error, undefined, 'auto.http.remix_v3.on_error');

// Chained so the app keeps its own response.
return appOnError?.(error);
};

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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).

See: https://github.com/remix-run/remix/blob/b4a78c9e90935672365a6acefeaabb287db1882c/packages/node-fetch-server/src/lib/request-listener.ts#L103

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice, updated

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>
@chargome

chargome commented Oct 1, 2026

Copy link
Copy Markdown
Member Author

bugbot run

Comment thread packages/remix/src/v3/server/instrument.ts

@cursor cursor Bot left a comment •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale Bugbot comment from a previous run.

@chargome
chargome merged commit ca0837d into develop Oct 1, 2026
514 of 521 checks passed
@chargome
chargome deleted the charlygomez/js-3767-complete-remix-3-server-error-handling branch October 1, 2026 15:09
@chargome

chargome commented Oct 2, 2026

Copy link
Copy Markdown
Member Author

bugbot run

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ 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.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Complete Remix 3 server error handling

2 participants