Skip to content

feat(node): Auto-register Koa error handler on app start - #23463

Draft
mydea wants to merge 5 commits into
developfrom
fn/koa-error-handler
Draft

feat(node): Auto-register Koa error handler on app start#23463
mydea wants to merge 5 commits into
developfrom
fn/koa-error-handler

Conversation

@mydea

@mydea mydea commented Aug 20, 2026

Copy link
Copy Markdown
Member

The Koa error handler is now registered automatically when the app starts, so setupKoaErrorHandler no longer needs to be called. This mirrors the Hapi change and removes the last manual setup step for Koa error capture.

How it works

Koa's Application is an EventEmitter and emits 'error' for every request error that bubbles up unhandled — the same set of errors a top-level try/catch middleware would see, but order-independent. So instead of injecting a try/catch middleware (whose position in the onion stack was load-bearing), we attach a single app.on('error') listener.

Auto-registration rides a new orchestrion channel on Application.prototype.callback. app.listen() always funnels through callback(), so this also covers http.createServer(app.callback()).

Decisions

  • Attach on the channel's end, not start. Koa registers its own default error listener inside callback() — but only if none exist yet (if (!this.listenerCount('error')) this.on('error', this.onerror)). Attaching before that runs would suppress koa's built-in error logging. Acting on end (after the method body) means koa's default listener is already in place and ours is added alongside it.
  • app.on('error') over a first-position try/catch middleware. Event listeners are additive and order-independent, so there is no ordering conflict with a user's own error handling: if a user middleware catches and handles an error, koa never emits and we correctly don't capture; if it's unhandled, our listener and any user app.on('error') both run.
  • setupKoaErrorHandler stays as an idempotent delegate (deprecated) rather than a hard no-op, so a direct call still works without orchestrion (e.g. error capture with tracing disabled). An idempotency marker on the app means auto-registration plus a manual call never stack up duplicate listeners.
  • attachKoaErrorHandler is also deprecated and marked internal — it exists only so the deprecated setupKoaErrorHandler can delegate to it, and should not be called directly.
  • The Koa integration files were collocated into a koa/ folder to match the Hapi layout.

Auto-registration is exercised end-to-end by dropping the manual call from the koa integration-test scenario and the e2e app; a new unit suite covers the attach behaviour (single idempotent listener, guards, and capture mechanism).

A follow-up will do the same for Express.

mydea and others added 2 commits August 20, 2026 11:55
The Koa error handler now registers itself automatically when the app starts, so
`setupKoaErrorHandler` no longer needs to be called. The handler is attached as an
order-independent `app.on('error')` listener via a new orchestrion `callback`
channel; the listener is added after koa registers its own default error listener
so koa's built-in error logging is preserved.

`setupKoaErrorHandler` and the shared `attachKoaErrorHandler` are both deprecated;
`setupKoaErrorHandler` remains an idempotent delegate for backwards compatibility.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

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

Cursor Bugbot has reviewed your changes and found 3 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit e8b1047. Configure here.

Comment thread packages/server-utils/src/integrations/koa/index.ts
Comment thread packages/server-utils/src/integrations/koa/koa-error-handler.ts
Comment thread packages/node/src/integrations/tracing/koa.ts
@github-actions

github-actions Bot commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

size-limit report 📦

Path Size % Change Change
@sentry/browser 30.3 kB - -
@sentry/browser - with treeshaking flags 28.47 kB - -
@sentry/browser - with treeshaking flags tracing without tracing 26.81 kB - -
@sentry/browser (incl. Tracing) 48.58 kB - -
@sentry/browser (incl. Tracing + Span Streaming) 48.59 kB - -
@sentry/browser (incl. Tracing, Profiling) 51.46 kB - -
@sentry/browser (incl. Tracing, Replay) 87.98 kB - -
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags 77.36 kB - -
@sentry/browser (incl. Tracing, Replay with Canvas) 92.7 kB - -
@sentry/browser (incl. Tracing, Replay, Feedback) 105.39 kB - -
@sentry/browser (incl. Feedback) 47.65 kB - -
@sentry/browser (incl. sendFeedback) 35.13 kB - -
@sentry/browser (incl. FeedbackAsync) 40.28 kB - -
@sentry/browser (incl. Metrics) 31.24 kB - -
@sentry/browser (incl. Logs) 31.52 kB - -
@sentry/browser (incl. Metrics & Logs) 32.15 kB - -
@sentry/react 32.09 kB - -
@sentry/react (incl. Tracing) 50.77 kB - -
@sentry/vue 35.34 kB - -
@sentry/vue (incl. Tracing) 50.54 kB - -
@sentry/svelte 30.33 kB - -
CDN Bundle 31.61 kB - -
CDN Bundle (incl. Tracing) 48.9 kB - -
CDN Bundle (incl. Logs, Metrics) 33.8 kB - -
CDN Bundle (incl. Tracing, Logs, Metrics) 50.82 kB - -
CDN Bundle (incl. Replay, Logs, Metrics) 74.31 kB - -
CDN Bundle (incl. Tracing, Replay) 86.48 kB - -
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) 88.31 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback) 92.19 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) 94.12 kB - -
CDN Bundle - uncompressed 93.84 kB - -
CDN Bundle (incl. Tracing) - uncompressed 146.75 kB - -
CDN Bundle (incl. Logs, Metrics) - uncompressed 100.14 kB - -
CDN Bundle (incl. Tracing, Logs, Metrics) - uncompressed 152.44 kB - -
CDN Bundle (incl. Replay, Logs, Metrics) - uncompressed 229.08 kB - -
CDN Bundle (incl. Tracing, Replay) - uncompressed 266.01 kB - -
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed 271.68 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed 279.71 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed 285.37 kB - -
@sentry/nextjs (client) 53.29 kB - -
@sentry/sveltekit (client) 49 kB - -
@sentry/core/server 65.38 kB - -
@sentry/core/browser 51.72 kB - -
@sentry/node 117.14 kB +0.14% +154 B 🔺
@sentry/node/import (ESM hook with diagnostics-channel injection) 0 B added added
@sentry/node - without tracing 81.47 kB +0.05% +34 B 🔺
@sentry/aws-serverless 90.94 kB +0.04% +33 B 🔺
@sentry/cloudflare (withSentry) - minified 213.98 kB - -
@sentry/cloudflare (withSentry) 528.93 kB - -

View base workflow run

@mydea
mydea marked this pull request as ready for review August 20, 2026 11:16
@mydea
mydea requested review from a team as code owners August 20, 2026 11:16
@mydea
mydea requested review from JPeer264, chargome, isaacs and s1gr1d and removed request for a team August 20, 2026 11:16
@mydea
mydea marked this pull request as draft August 20, 2026 11:33
timestamp: expect.any(Number),
trace_id: expect.stringMatching(/[a-f0-9]{32}/),
},
{

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.

we do not add a middleware ourselves anymore, so this disappears 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.

1 participant