Skip to content

ref(hono): move shared Hono instrumentation into @sentry/server-utils - #24496

Merged
mydea merged 3 commits into
developfrom
feat/hono-move-to-server-utils
Sep 30, 2026
Merged

mydea merged 3 commits into
developfrom
feat/hono-move-to-server-utils

Conversation

@mydea

@mydea mydea commented Sep 18, 2026 •

Copy link
Copy Markdown
Member

First of two stacked PRs splitting the Hono instrumentation rework (originally #24371).

Relocates the runtime-agnostic Hono instrumentation out of @sentry/hono into @sentry/server-utils (src/integrations/hono/), with @sentry/hono re-exporting it. Since @sentry/server-utils must not depend on hono, the relocated code no longer imports it: the Hono class is passed in by the SDK and a vendored honoTypes module provides the shapes. The sentry() middleware now builds its request handler via the shared createHonoRequestMiddleware. Pure relocation — no behavior change.

Also renames the hono-4 e2e test app to hono-4-legacy and moves the corresponding unit tests alongside the relocated code.

The orchestrion-based auto-instrumentation that builds on this lives in the stacked PR #24497.

🤖 Generated with Claude Code

@mydea
mydea added this pull request to stack #24498 September 18, 2026 10:39

@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/server-utils/src/integrations/hono/wrapMiddlewareSpan.ts
@github-actions

github-actions Bot commented Sep 18, 2026 •

Copy link
Copy Markdown
Contributor

size-limit report 📦

Path Size % Change Change
@sentry/browser 29.24 kB - -
@sentry/browser - with treeshaking flags 27.5 kB - -
@sentry/browser - with treeshaking flags tracing without tracing 27.4 kB - -
@sentry/browser (incl. Tracing) 51.15 kB - -
@sentry/browser (incl. Tracing + Span Streaming) 51.18 kB - -
@sentry/browser (incl. Tracing, Profiling) 54.18 kB - -
@sentry/browser (incl. Tracing, Replay) 90.76 kB - -
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags 79.86 kB - -
@sentry/browser (incl. Tracing, Replay with Canvas) 95.46 kB - -
@sentry/browser (incl. Tracing, Replay, Feedback) 108.41 kB - -
@sentry/browser (incl. Feedback) 46.76 kB - -
@sentry/browser (incl. sendFeedback) 34.3 kB - -
@sentry/browser (incl. FeedbackAsync) 39.41 kB - -
@sentry/browser (incl. Metrics) 30.25 kB - -
@sentry/browser (incl. Logs) 30.53 kB - -
@sentry/browser (incl. Metrics & Logs) 31.2 kB - -
@sentry/react 31.08 kB - -
@sentry/react (incl. Tracing) 53.54 kB - -
@sentry/vue 36.74 kB - -
@sentry/vue (incl. Tracing) 53.7 kB - -
@sentry/svelte 29.26 kB - -
CDN Bundle 31.05 kB - -
CDN Bundle (incl. Tracing) 51.8 kB - -
CDN Bundle (incl. Logs, Metrics) 33.31 kB - -
CDN Bundle (incl. Tracing, Logs, Metrics) 53.77 kB - -
CDN Bundle (incl. Replay, Logs, Metrics) 74.02 kB - -
CDN Bundle (incl. Tracing, Replay) 89.39 kB - -
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) 91.36 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback) 95.55 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) 97.53 kB - -
CDN Bundle - uncompressed 91.7 kB - -
CDN Bundle (incl. Tracing) - uncompressed 154.08 kB - -
CDN Bundle (incl. Logs, Metrics) - uncompressed 98.27 kB - -
CDN Bundle (incl. Tracing, Logs, Metrics) - uncompressed 160.04 kB - -
CDN Bundle (incl. Replay, Logs, Metrics) - uncompressed 227.84 kB - -
CDN Bundle (incl. Tracing, Replay) - uncompressed 273.81 kB - -
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed 279.75 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed 287.51 kB - -
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed 293.44 kB - -
@sentry/nextjs (client) 55.78 kB - -
@sentry/sveltekit (client) 51.6 kB - -
@sentry/core/server 39.99 kB - -
@sentry/core/browser 13.63 kB - -
@sentry/node 142.26 kB +0.01% +10 B 🔺
@sentry/node/import (ESM hook with diagnostics-channel injection) 82.88 kB - -
@sentry/node - without tracing 91.25 kB +0.02% +15 B 🔺
@sentry/node - without channel injection 120.66 kB +0.01% +9 B 🔺
@sentry/aws-serverless 99.52 kB +0.01% +7 B 🔺
@sentry/cloudflare (withSentry) - minified 206.69 kB - -
@sentry/cloudflare (withSentry) 514.13 kB - -

View base workflow 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.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

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 09ebc47. Configure here.

Comment thread packages/hono/src/cloudflare/middleware.ts Outdated

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

LGTM, only one comment about the deleted tests.

Comment on lines +186 to +197
test.describe('error inside internal fetch (degraded response)', () => {
// The manual `sentry()` middleware only instruments the main app's request lifecycle. An error
// thrown solely inside an internal sub-app `.request()` — whose failed response the outer handler
// swallows — is therefore NOT captured here, unlike the orchestrion auto-instrumentation in the
// `hono-4` app, which instruments every dispatched context. We assert only that the outer request
// stays healthy.
test('degrades to a 200 when the inner route fails', async ({ baseURL }) => {
const response = await fetch(`${baseURL}${STOREFRONT}/product/self-watering-plant/degraded`);
expect(response.status).toBe(200);
await expect(response.json()).resolves.toEqual({ product: null, degraded: true });
});
});

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 should be a follow-up fix.

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.

Why was this and wrapMiddlewareSpan deleted?

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'd need to export this from server-utils to be able to test this in the hono package 😢 not 100% sure...

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.

ohhh 😬 then we should at least test this E2E

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.

I added some node-integration tests etc. to cover the things that we used to cover before. I think coverage should be decent now!

@mydea
mydea marked this pull request as ready for review September 21, 2026 12:43
@mydea
mydea requested review from a team as code owners September 21, 2026 12:43
@mydea
mydea requested review from chargome and nicohrubec and removed request for a team September 21, 2026 12:43

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

Thanks for splitting that up

@mydea
mydea force-pushed the feat/hono-move-to-server-utils branch from 9f3e320 to dd97746 Compare September 29, 2026 07:41
@mydea
mydea requested a review from a team as a code owner September 29, 2026 07:41
@mydea
mydea requested review from andreiborza and isaacs and removed request for a team September 29, 2026 07:41
@mydea
mydea force-pushed the feat/hono-move-to-server-utils branch from dd97746 to 153b2e1 Compare September 29, 2026 12:15
mydea and others added 3 commits September 30, 2026 08:59
Relocate the runtime-agnostic Hono instrumentation out of `@sentry/hono` into
`packages/server-utils/src/integrations/hono/`, with `@sentry/hono` re-exporting
it. Server-utils must not depend on `hono`, so the relocated code no longer
imports it (the `Hono` class is passed in by the SDK and a vendored `honoTypes`
provides the shapes). The `sentry()` middleware now builds its request handler
via the shared `createHonoRequestMiddleware`. No behavior change.

Also renames the `hono-4` e2e test app to `hono-4-legacy` and moves the
corresponding unit tests alongside the relocated code.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Align the middleware definitions and assertions in the hono-4-legacy e2e app with
the hono-4 app: anonymous function expressions (name inferred from the const
binding, stable when bundled), a unique per-throw error suffix, and matching error
assertions. Add a named-function middleware case, and a degraded-response test that
documents the manual sentry() middleware does not capture errors thrown solely
inside an internal sub-app .request() (unlike the auto-instrumentation).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The Cloudflare and Deno Hono adapters imported applyHonoPatches, earlyPatchHono
and createHonoRequestMiddleware from the main @sentry/server-utils entry, whose
barrel also loads node:diagnostics_channel and other Node-only modules — which can
fail at import/bundle time on Cloudflare Workers and Deno.

Export the runtime-agnostic helpers from `exports.ts` (shared by both entries),
sourced directly from their modules rather than the ./integrations/hono barrel, so
they are available from @sentry/server-utils/no-diagnostic-channels without pulling
in diagnostics-channel. Point the Cloudflare and Deno adapters at that Node-free
entry. Also move the applyHonoPatches wrapper out of the barrel into the Node-free
applyPatches module.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@mydea
mydea force-pushed the feat/hono-move-to-server-utils branch from 153b2e1 to cd73831 Compare September 30, 2026 07:00
}

if (input instanceof Request) {
return new URL(input.url).pathname;

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: The extractPathname function can crash on Request objects with malformed URLs. The call to new URL(input.url) lacks a try...catch block, violating the function's "must never throw" contract.
Severity: HIGH

Suggested Fix

Wrap the new URL(input.url).pathname call within a try...catch block, similar to the handling for string inputs. In the catch block, return a fallback pathname, for example by using the stripQueryAndHash(input.url) utility, to ensure the function never throws an exception.

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/server-utils/src/integrations/hono/patchAppRequest.ts#L66

Potential issue: The `extractPathname` function does not handle potential errors when
parsing the URL from a `Request` object. Specifically, the line `new
URL(input.url).pathname` is not wrapped in a `try...catch` block. While most `Request`
objects have valid URLs, runtimes like Cloudflare Workers can create `Request` objects
with malformed URLs, such as those with invalid percent-encoding. In such cases, `new
URL()` will throw an exception, causing an unhandled error that crashes the request
handler. This violates the function's documented contract that it "must never throw" and
creates an inconsistency with the string-based input path, which does include error
handling.

Did we get this right? 👍 / 👎 to inform future reviews.

@mydea
mydea merged commit a06c37f into develop Sep 30, 2026
346 checks passed
@mydea
mydea deleted the feat/hono-move-to-server-utils branch September 30, 2026 12:18
mydea added a commit that referenced this pull request Sep 30, 2026
Second of two stacked PRs splitting the Hono instrumentation rework
(originally #24371). Stacked on #24496 — review/merge that first; the
diff here is against the base PR's branch.

Adds `honoIntegration`, the auto-instrumentation that hooks Hono through
the orchestrion module transform (`node:diagnostics_channel`) so
requests are route-enriched without a manual `sentry()` middleware, plus
its manual counterpart `honoMiddleware`. Registers it in
`getErrorIntegrations()` and re-exports both from the server runtimes
(node, cloudflare, bun, deno, and the serverless / meta-framework
packages).

Also adds the orchestrion transform config for `hono`,
node-integration-tests for the auto-instrumentation, and a new
orchestrion-based `hono-4` e2e app (the middleware-based app now lives
as `hono-4-legacy`, added in the base PR). `node-mastra` now asserts
route-enriched Hono spans in prod, where Hono is external and
orchestrion-instrumented.

_Root cause / notable fix:_ pulling the Hono module into the Cloudflare
barrel reshuffled the worker bundle's module-init order and surfaced a
latent TDZ crash for provided-module integrations (Flue): `Cannot access
'flueIntegration' before initialization` at worker startup. The
orchestrion snippet injected into each instrumented module passed the
integration factory **by reference**, reading the binding the instant
that module evaluated — and since `@sentry/*/vite` imports a
provided-module integration back into its own instrumented package, that
closes an import cycle. The snippet now wraps the factory in an arrow
(`() => flueIntegration()`) so the binding is only read when the stored
thunk runs at `init()`, breaking the cycle.

Also folds in a few follow-ups: `honoMiddleware` is now exported from
the remaining runtimes that only had `honoIntegration` (elysia, remix,
solidstart, sveltekit), the shared `INTERNAL_REQUEST_ORIGIN` constant
moved into `hono/constants.ts`, and the previously-skipped `.basePath()`
middleware e2e test is unskipped — the per-request orchestrion hook
discovers middleware from the matched-handler list at dispatch, so it
now works on the clone `.basePath()` returns.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: isaacs <i@izs.me>
Co-authored-by: Jan Peer Stöcklmair <jan.oster94@gmail.com>
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