Skip to content

feat(express)!: Remove shouldHandleError from setupExpressErrorHandler - #23732

Merged
s1gr1d merged 5 commits into
developfrom
sig/express-handleError
Aug 31, 2026
Merged

feat(express)!: Remove shouldHandleError from setupExpressErrorHandler#23732
s1gr1d merged 5 commits into
developfrom
sig/express-handleError

Conversation

@s1gr1d

@s1gr1d s1gr1d commented Aug 28, 2026

Copy link
Copy Markdown
Member

shouldHandleError now lives only on expressIntegration().

setupExpressErrorHandler and expressErrorHandler no longer accept the option, and the ExpressHandlerOptions type is removed.

This finishes #23464: the integration owns error capture, so it should own the filter too. Fastify and Hapi already work this way.

The deprecated setupExpressErrorHandler still captures when the integration cannot (setups where orchestrion does not work). But filtering keeps working on the expressIntegration. It captures 5xx errors and errors without a status, and cannot be filtered. Filtering is the reason to migrate to expressIntegration().


First merge this one:

@s1gr1d
s1gr1d requested review from a team as code owners August 28, 2026 12:08
@s1gr1d
s1gr1d requested review from JPeer264 and isaacs and removed request for a team August 28, 2026 12:08
@github-actions

github-actions Bot commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

size-limit report 📦

⚠️ Warning: Base artifact is not the latest one, because the latest workflow run is not done yet. This may lead to incorrect results. Try to re-run all tests to get up to date results.

Path Size % Change Change
@sentry/browser 28.56 kB - -
@sentry/browser - with treeshaking flags 26.92 kB - -
@sentry/browser - with treeshaking flags tracing without tracing 26.82 kB - -
@sentry/browser (incl. Tracing) 48.75 kB - -
@sentry/browser (incl. Tracing + Span Streaming) 48.76 kB - -
@sentry/browser (incl. Tracing, Profiling) 51.68 kB - -
@sentry/browser (incl. Tracing, Replay) 88.23 kB - -
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags 77.63 kB - -
@sentry/browser (incl. Tracing, Replay with Canvas) 92.93 kB - -
@sentry/browser (incl. Tracing, Replay, Feedback) 105.85 kB - -
@sentry/browser (incl. Feedback) 46.05 kB - -
@sentry/browser (incl. sendFeedback) 33.62 kB - -
@sentry/browser (incl. FeedbackAsync) 38.73 kB - -
@sentry/browser (incl. Metrics) 29.51 kB - -
@sentry/browser (incl. Logs) 29.8 kB - -
@sentry/browser (incl. Metrics & Logs) 30.43 kB - -
@sentry/react 30.3 kB - -
@sentry/react (incl. Tracing) 50.94 kB - -
@sentry/vue 35.73 kB - -
@sentry/vue (incl. Tracing) 51.02 kB - -
@sentry/svelte 28.59 kB - -
CDN Bundle 30.35 kB - -
CDN Bundle (incl. Tracing) 49.38 kB - -
CDN Bundle (incl. Logs, Metrics) 32.58 kB - -
CDN Bundle (incl. Tracing, Logs, Metrics) 51.25 kB - -
CDN Bundle (incl. Replay, Logs, Metrics) 73.17 kB - -
CDN Bundle (incl. Tracing, Replay) 86.86 kB - -
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) 88.73 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback) 92.8 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) 94.64 kB - -
CDN Bundle - uncompressed 89.95 kB - -
CDN Bundle (incl. Tracing) - uncompressed 147.2 kB - -
CDN Bundle (incl. Logs, Metrics) - uncompressed 96.24 kB - -
CDN Bundle (incl. Tracing, Logs, Metrics) - uncompressed 152.89 kB - -
CDN Bundle (incl. Replay, Logs, Metrics) - uncompressed 225.41 kB - -
CDN Bundle (incl. Tracing, Replay) - uncompressed 266.69 kB - -
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed 272.37 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed 280.4 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed 286.06 kB - -
@sentry/nextjs (client) 53.51 kB - -
@sentry/sveltekit (client) 49.19 kB - -
@sentry/core/server 65.67 kB - -
@sentry/core/browser 51.86 kB - -
@sentry/node 123.52 kB +0.02% +20 B 🔺
@sentry/node/import (ESM hook with diagnostics-channel injection) 85.23 kB - -
@sentry/node - without tracing 87.78 kB +0.03% +22 B 🔺
@sentry/node - without channel injection 103.18 kB +0.03% +22 B 🔺
@sentry/aws-serverless 96.12 kB +0.03% +24 B 🔺
@sentry/cloudflare (withSentry) - minified 200.72 kB - -
@sentry/cloudflare (withSentry) 499.25 kB - -

View base workflow run

Base automatically changed from sig/express-error-tests to develop August 28, 2026 15:27

@isaacs isaacs left a comment

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.

This accomplishes the stated goal to make expressIntegration() the single owner of the error filter and match the fastify pattern.

Most of the comments below are pretty minor cleanup opportunities. The type name confusion between core and server-utils might be worth cleaning up now, but can also be done in a subsequent follow-up.

The bigger opportunity for improvement would be adding an E2E test for the new runtime path added. That is: the integration is registered with a custom shouldHandleError, the orchestrion transform is not active, so the deprecated middleware captures, and reads the predicate off the integration. Nothing exercises that end to end, might be worth just telling an agent to add an e2d for that, so it's part of our covered contract.

That said, it seems to be working, so probably fine either way.

/* oxlint-disable typescript/no-deprecated -- deprecated Express error-handler exports, kept until the next major */
export { expressErrorHandler, setupExpressErrorHandler } from './integrations/express/error-handler';
export type { ExpressHandlerOptions } from './integrations/express/types';
export type { ExpressIntegrationOptions } from './integrations/express/types';

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.

This is a bit minor, but could be confusing. @sentry/core already exports a different ExpressIntegrationOptions (in packages/core/src/server-exports.ts line 23, defined at packages/core/src/integrations/express/types.ts lines 147-153.)

The core version is deprecated, and doesn't have shouldHandleError. This one isn't actually accessible, since it's not re-exported by @sentry/node.

This can certainly be cleaned up in a followup, but I think it would be best to coalesce these into a single type (either defined in core, or here, but not both).

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.

Yes, this makes sense and can be done in a follow-up 👍

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.

Done here: #23763

@@ -53,7 +53,7 @@ export { vercelAIIntegration } from './integrations/vercel-ai';
export { expressIntegration } from './integrations/express';
/* oxlint-disable typescript/no-deprecated -- deprecated Express error-handler exports, kept until the next major */

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.

I don't think any deprecated items are being pulled in here, are they? It's the one in core that's deprecated, this one isn't.

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.

Those exports are deprecated as well

if (shouldHandleError(error)) {
// `shouldHandleError` is configured on `expressIntegration()` only. Without the integration
// registered, the default predicate applies.
if (shouldCaptureError(getExpressIntegration()?.getShouldHandleError(), 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.

Suggested change
if (shouldCaptureError(getExpressIntegration()?.getShouldHandleError(), error)) {
if (shouldCaptureError(getExpressIntegration()?.getShouldHandleError?.(), error)) {

Unlikely edge case, but if the Express integration name is used by something that doesn't have this method, it'd throw.

Comment thread MIGRATION.md Outdated
+ integrations: [
+ Sentry.expressIntegration({
+ shouldHandleError(error) {
+ return (error.statusCode ?? 500) >= 400;

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.

Suggested change
+ return (error.statusCode ?? 500) >= 400;
+ return Number(error.statusCode ?? 500) >= 400;

low: error.statusCode can be a string.

* 5xx errors, and treats an error without a resolvable status as a 500. Errors
* carrying a 3xx/4xx status are skipped (client errors / redirects).
*/
export function defaultShouldHandleError(error: MiddlewareError): boolean {

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.

low: Does anything else use this? If it's only used internally, I don't think we still need to export it.

# Conflicts:
#	MIGRATION.md
#	packages/server-utils/test/integrations/express-error-handler.test.ts
@s1gr1d
s1gr1d merged commit e32ea1f into develop Aug 31, 2026
552 of 554 checks passed
@s1gr1d
s1gr1d deleted the sig/express-handleError branch August 31, 2026 14:59
s1gr1d added a commit that referenced this pull request Aug 31, 2026
…ndler` and `setupFasitfyErrorHandler` (#23734)

Express:
- #23732
- #23464
- #23763
Fastify:
- #23460
- #23464
- #23411
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.

3 participants