meta(changelog): Update changelog for 11.0.0-rc.1 - #24562
Merged
Merged
Conversation
…nd Vite versions (#24437) Until now, only Vite 8 used the fast (non-Babel) React component annotation transform. Rollup and Vite 5-7 always went through Babel. This PR moves every Rollup and Vite version to the fast path, as a first step toward removing Babel. Rollup's own `parseAstAsync`, which Vite 5-7 re-export, can't parse TypeScript, and the Vite plugin runs with `enforce: 'pre'`, so it sees raw `.tsx`. So this adds `oxc-parser` as a dependency for those versions. Vite 8 keeps using its own parser. `oxc-parser` needs `preserveParens: false` to give the same AST as Vite 8. It also returns syntax errors instead of throwing them, so the adapter throws on errors, and those files still fall back to Babel. Babel also stays as the fallback on platforms without an `oxc-parser` native binding. The walker's parity tests with Babel previously ran only on the Babel parser's AST. They now also run on `oxc-parser` output, which matches what Vite 8 produces. Ref #24415
Consolidate the nearly (but not exactly!) identical fetch integrations used by deno, bun, cloudflare, and vercel-edge. The deno `breadcrumbs` integration is folded in, and the separate integration is deprecated. The functionality is placed in `@sentry/core` rather than `@sentry/server-utils` in order to avoid leaking node internals where they don't belong. Node and Browser fetch integrations are not touched, because they use completely different mechanisms. closes JS-3667 closes #24344
…4450) `instrumentDurableObjectNamespace` special-cases `get` and `getByName`, and binds every other function to the raw target. `jurisdiction()` therefore returned an uninstrumented namespace, so stubs from a jurisdiction-restricted namespace got no fetch span and never appended `__sentry_rpc_meta__`. Apps using data-location jurisdictions (for example EU residency) lost trace continuity at every Durable Object call. `jurisdiction()` now returns a namespace instrumented the same way as its parent, with the same `propagateRpcTrace` setting. This has unit coverage only: local workerd throws "Jurisdiction restrictions are not implemented in workerd", so an integration suite can't exercise it. Split out of #24447, which now covers #24443 only. Fixes #24442 - [x] If you've added code that should be tested, please add tests. - [x] Ensure your code lints and the test suite passes (`yarn lint`) & (`yarn test`). - [x] Link an issue if there is one related to your pull request. If no issue is linked, one will be auto-generated and linked. _Written with AI assistance (Claude Code)._ Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Stacked on #24265 — review that first, this is tests only. Unit coverage for the instrumentation, plus an integration suite that drives an agent through a tool call and asserts the `invoke_agent` → `chat` / `execute_tool` hierarchy — including that tool spans are siblings of `chat` rather than children, matching how Flue's own OpenTelemetry adapter projects them. The scenario uses `pi-ai`'s `faux` provider so responses are scripted in-process and no provider key is needed. It is ESM only (`@flue/runtime` has no `require` export condition) and installed per-suite, since `engines.node >= 22.19` would break `yarn install` on the Node 20 lane. Guarded by `conditionalTest({ min: 22 })`, so it skips on the repo's default Node 20. Each case was mutation-tested rather than just run green, which is what caught the tests that passed vacuously and an unreachable branch in `trackSpan` that has since been removed. --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Stacked on #24266 — review that first, this is the e2e app only. The node-integration-test calls `__flueBindAgentModule` by hand, standing in for what `@flue/vite` does from the `'use agent'` directive, so it can't show whether a scaffolded app actually works. This is `flue init` output, built and served the way a user runs it, against a real provider. Covered, in both dev and prod and in both the base and orchestrion variants: - `invoke_agent` / `chat` / `execute_tool` with usage and cost - a thrown tool error becoming an issue - a manual span inside a tool nesting under `execute_tool` - an orchestrion-instrumented `dataloader` span landing in the agent's trace - the provider's `http.client` call nesting inside `chat` The loader runs inside a tool rather than a route so its span shares the agent's trace. No build externals are needed unlike `node-eve` — a Flue node build leaves dependencies as bare specifiers, so `dataloader` stays a real module for the transform to hook. `@flue/*` is pinned because the internal registry proxy 403s on releases it hasn't scanned. _Found_: a thrown tool error produced an errored span and no issue at all, since Flue catches the throw and hands it back to the model as a tool result. Fixed in #24265. --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
…alls (#24447) Durable Object RPC methods only got a Sentry client when the call carried `__sentry_rpc_meta__`. Every other call ran with no client, so its errors, logs and metrics were dropped. That covers calls from uninstrumented workers, calls made outside the request's async context, and every call through `jurisdiction()`. `jurisdiction()` itself bypassed `instrumentDurableObjectNamespace`, so its stubs never propagated a trace. External RPC calls without metadata now run capture-only (client, isolation scope and flush, but no span), which is what `instrumentWorkerEntrypoint` already does. `jurisdiction()` now returns a namespace that is instrumented the same way as the parent. Some decisions worth calling out: - **Telling external calls from internal ones.** RPC methods are wrapped on the prototype (#23040), so a `this.helper()` call reaches the same wrapper as an external call. workerd dispatches an incoming RPC call outside any async context, so the wrapper treats a call made while an invocation is already in flight (isolation scope is not the default) as internal and runs the original method. Returning a proxy of the instance, as `instrumentWorkerEntrypoint` does, would bring back the private-field breakage from #23040. That's why the change only touches Durable Objects. - **`startNewTrace` for untraced calls, unlike WorkerEntrypoint.** A Durable Object instance is long-lived and serves overlapping calls. Without a new trace, every untraced call inherits the propagation context of the default scope, so unrelated calls share one trace id. The overlapping-calls unit test fails without it. Fixes #24443 - [x] If you've added code that should be tested, please add tests. - [x] Ensure your code lints and the test suite passes (`yarn lint`) & (`yarn test`). - [x] Link an issue if there is one related to your pull request. If no issue is linked, one will be auto-generated and linked. _Written with AI assistance (Claude Code)._ --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com> Co-authored-by: Jan Peer Stöcklmair <jan.peer@sentry.io>
…fers (#24462) `withSentryConfig` detected the Next.js version by resolving `next/package.json` from `process.cwd()` only. When the process starts outside the Next.js project root (custom servers, monorepos started from the repo root, supervisors with their own cwd), detection returns `undefined` and the SDK silently falls back to the Next 14 config shape. On Next 15+ this means `serverExternalPackages` is never set, and Next warns about the unrecognized `experimental` keys. Resolution now still tries `process.cwd()` first, so the project's own `next` wins in the normal case, and falls back to resolving from the SDK's own location. `next` is a peer dependency, so it's reachable from there even under pnpm's isolated installs. Fixes #24461 Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Nuxt 5 switched on its Nitro v2 compatibility layer for any module whose server code imports `h3`: nuxt/nuxt#36318 The hook now recognizes h3 errors the way h3 itself does, without importing it: h3 v2 by the error's `name`, h3 v1 by the static `__h3_error__` flag on the class. Both expose `statusCode`. Our CI tests currently show this warning: ``` [WebServer] [warn] [NUXT_B9003] Nitro v2 compatibility was applied to server code from 1 module, because of what it imports: [WebServer] - `@sentry/nuxt/module` (imports `h3`) [WebServer] ╰▶ fix: This layer is transitional and will be removed in Nuxt 6. Update the module to import from `nuxt/server`, registering the portable file alongside the one it ships today, or report it to the module author if the module is not your own. ```
Koa instrumentation already declares `>=2.0.0 <4` and hooks nothing that changed in Koa 3, but only Koa 2 was tested, so the integration suite now runs against both majors. Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Bumps [devalue](https://github.com/sveltejs/devalue) from 5.9.0 to 5.9.2. <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/sveltejs/devalue/releases">devalue's releases</a>.</em></p> <blockquote> <h2>v5.9.2</h2> <h3>Patch Changes</h3> <ul> <li>8b2a456: fix: reject out-of-bounds indices</li> </ul> <h2>v5.9.1</h2> <h3>Patch Changes</h3> <ul> <li>39457ce: fix: <code>uneval</code> emits valid JS for graphs with more than 65534 repeated references</li> <li>686e379: fix: emit valid JS for Node <code>Buffer</code> in <code>uneval</code></li> <li>376b65c: fix: preserve <code>-0</code> in float typed arrays in <code>uneval</code></li> </ul> </blockquote> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/sveltejs/devalue/blob/main/CHANGELOG.md">devalue's changelog</a>.</em></p> <blockquote> <h2>5.9.2</h2> <h3>Patch Changes</h3> <ul> <li>8b2a456: fix: reject out-of-bounds indices</li> </ul> <h2>5.9.1</h2> <h3>Patch Changes</h3> <ul> <li>39457ce: fix: <code>uneval</code> emits valid JS for graphs with more than 65534 repeated references</li> <li>686e379: fix: emit valid JS for Node <code>Buffer</code> in <code>uneval</code></li> <li>376b65c: fix: preserve <code>-0</code> in float typed arrays in <code>uneval</code></li> </ul> </blockquote> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/sveltejs/devalue/commit/a3d30d94c8fd9cfca4b774814ff9d5bfade5010c"><code>a3d30d9</code></a> Version Packages (<a href="https://redirect.github.com/sveltejs/devalue/issues/180">#180</a>)</li> <li><a href="https://github.com/sveltejs/devalue/commit/8b2a4562c446d7c36d9d629778079a5fae4243e1"><code>8b2a456</code></a> Merge commit from fork</li> <li><a href="https://github.com/sveltejs/devalue/commit/3e01a6c749e215e16c94f5c132f46f7840dfa5e0"><code>3e01a6c</code></a> Version Packages (<a href="https://redirect.github.com/sveltejs/devalue/issues/179">#179</a>)</li> <li><a href="https://github.com/sveltejs/devalue/commit/686e3792db1c96bd036d126ba282eb13705704f6"><code>686e379</code></a> fix: emit valid JS for Node <code>Buffer</code> in <code>uneval</code> (<a href="https://redirect.github.com/sveltejs/devalue/issues/175">#175</a>)</li> <li><a href="https://github.com/sveltejs/devalue/commit/39457ce1eed1cd7ea3d2b6e90b5c5eb3d4626b40"><code>39457ce</code></a> fix: uneval emits valid JS for graphs with more than 65534 repeated reference...</li> <li><a href="https://github.com/sveltejs/devalue/commit/376b65cd0e9c7bd254c0921e96cab0038c3b7a7a"><code>376b65c</code></a> fix: preserve -0 in float typed arrays in uneval (<a href="https://redirect.github.com/sveltejs/devalue/issues/178">#178</a>)</li> <li>See full diff in <a href="https://github.com/sveltejs/devalue/compare/v5.9.0...v5.9.2">compare view</a></li> </ul> </details> <br /> [](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/getsentry/sentry-javascript/network/alerts). </details> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Adds auto-instrumentation for the `groq-sdk` and `together-ai` clients — chat completions and embeddings, streaming and non-streaming. Both are Stainless-generated SDKs that speak the OpenAI wire format, so rather than duplicating the openai integration twice, a shared `createOpenAiCompatibleIntegration` factory reuses the existing `ai/openai` span-building, streaming and response-parsing logic and only overrides `gen_ai.provider.name` and the span origin. Each provider is then a small orchestrion config + a one-call integration file, so the next OpenAI-compatible provider (Perplexity, Cerebras, …) is ~15 lines on the same rail. Groq is the meaningful one by volume (~3.4M npm downloads/mo); Together is included since it shares the exact layout at no extra cost. `gen_ai.request.max_tokens` is intentionally not asserted — the shared openai request extractor doesn't capture it today (a separate, pre-existing gap), so these providers match its behaviour. --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…24279) Adds `@sentry-internal/test-utils/cli`, a helper module for E2E apps that send real data to Sentry and have to wait until it is queryable. It shells out to the `sentry` CLI (`sentry trace view <org>/<project>/<trace> --json --fresh`) instead of hand-rolling requests against the organization trace endpoint, and exposes `findErrorInTrace`, `findSpanInTrace`, `fetchTrace`, `flattenTrace`, `traceTarget` and `EVENT_POLLING_OPTIONS`. Decisions: - The CLI itself is a dev dependency of the consuming app (the `sentry` package on npm), not of test-utils. The helper runs `pnpm exec sentry` in the app's working directory, which keeps the 15 MB CLI out of every other test app. - The helper hands `E2E_TEST_AUTH_TOKEN` to the CLI as `SENTRY_AUTH_TOKEN` and sets `SENTRY_FORCE_ENV_TOKEN=1`. Without the flag the CLI prefers a developer's stored login over the env token, so local runs would authenticate differently from CI. - `--fresh` bypasses the CLI's response cache, which would otherwise defeat polling. - Exit code 23 ("not found") means the trace has not landed yet. The auth exit codes and a 401 or 403 in the output fail immediately, because waiting never fixes a token that lacks `org:read`. - A separate subpath export instead of the root index, so the dependency on the CLI stays with the apps that opt in. - `traceTarget` returns the CLI target, so a test can log a `sentry trace view ...` line that is paste-able into a terminal when a CI run fails. The first consumer is the Cloudflare send-to-sentry E2E app in the follow-up PR. `react-send-to-sentry` and `node-express-send-to-sentry` keep their fetch-based copies for now and can move over separately. Part of #23610 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> Co-authored-by: isaacs <i@izs.me>
…o Sentry (#24280) Adds `cloudflare-workers-send-to-sentry`, an optional E2E app that deploys a real Cloudflare Worker and verifies in Sentry that the SDK's data arrives, in the spirit of `react-send-to-sentry`. Local `wrangler dev` cannot reproduce what the platform does around `waitUntil`, isolate reuse, Durable Object hibernation and eviction. This app is the place for tests that need the real runtime. The app is built with Vite, `@cloudflare/vite-plugin` and `sentryCloudflareVitePlugin()`, so the worker entry stays uninstrumented and the options live in `src/instrument.server.ts` via `defineCloudflareOptions`. Playwright's global setup deploys the Worker and waits for its workers.dev URL. The three tests cover a captured exception, an unhandled exception together with its request span, and a plain request span. They poll Sentry through `@sentry-internal/test-utils/cli` and log a paste-able `sentry trace view` command per trace. Decisions: - **One Worker per ref in CI, never deleted by the test run.** Pull requests and merge-queue runs deploy to `e2e-send-to-sentry-pr-<number>`, pushes to `e2e-send-to-sentry-<branch>` (`develop`, `master`, `v10`). A run overwrites the Worker of its ref, so a failed run leaves its Worker in place for debugging, and Workers Logs are enabled for it. The new `cleanup-e2e-workers.yml` workflow deletes the PR Worker when the PR closes. The branch Workers stay. Local runs use a throwaway `-local-<hex>` name that the teardown deletes; `E2E_KEEP_WORKER=1` keeps it. - **Redeploying is always done, never skipped.** A deploy takes about 10 s and the SDK tarball changes on almost every run. - **The unhandled-error test sends `baggage` next to `sentry-trace`.** The test has to pick the trace id itself, because a failed request cannot report ids. Without `baggage` the SDK freezes an empty dynamic sampling context (`propagationContextFromHeaders` in core, on purpose: "not head of trace"), and Relay drops the streamed span with the outcome `missing_dsc`. The error still arrives, only the request span is lost. This affects every server request whose upstream sends `sentry-trace` without `baggage` under span streaming. - **Only `CLOUDFLARE_ACCOUNT_ID` is required by the setup.** Wrangler authenticates with `CLOUDFLARE_API_TOKEN` in CI or a `wrangler login` session locally. Repository setup: `CLOUDFLARE_API_TOKEN` (Workers Scripts: Edit, Workers KV Storage: Read) and `CLOUDFLARE_ACCOUNT_ID` point at the Sentry Dev account, and the optional E2E job passes both through. Not in this PR: protecting the Worker URLs with Cloudflare Access and a service token. Worker-level Access rejects WebSocket upgrades, so it should be a hostname-based application per Worker, which needs "Access: Apps and Policies: Edit" on the API token. Verified with real runs against the Sentry Dev account: all three tests pass in about 1.3 minutes, and the throwaway Worker is deleted afterwards. Fixes #23610 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> Co-authored-by: isaacs <i@izs.me>
) closes #24484 closes [JS-3715](https://linear.app/getsentry/issue/JS-3715) Seems I forgot to update this in #22180
…ied chunks (#24022) While deploying our app (Next.js 16.2.10 turbopack build, `@sentry/nextjs` 10.68.0, `deleteSourcemapsAfterUpload: true`), we noticed some JS chunks were shipped cut off mid-file and threw `SyntaxError: Invalid or unexpected token` on every page load. We traced it to the sourceMappingURL stripping step, and this PR addresses it with a small regex change. The regex in `stripSourceMappingURLComments` doesn't check that the comment starts at the beginning of a line: ```js /\n?\/\/[#@] sourceMappingURL=[^\n]+$/ ``` So it also matches comment-shaped text inside a string literal — and since a minified chunk is a single line, everything from the match to EOF gets deleted: ```js // minified chunk — comment-shaped text inside a string const a=1;const worker='self.onmessage=()=>{};\n//# sourceMappingURL=worker.js.map\n';use(worker);const b=2; // after stripping — truncated mid-string, no longer parseable const a=1;const worker='self.onmessage=()=>{};\n ``` In our case the text came from rrweb (the recording engine behind Amplitude Session Replay), which inlines its worker code as a string. The regex is unchanged in 10.73.0 and on current develop. We fixed it by requiring the match to start at a line start — we've been running this in production via `pnpm patch`, upstreaming it in case it's useful: ```js /(?:^|\n)\/\/[#@] sourceMappingURL=[^\s'"`]+$/ ``` While digging around we noticed the repo already does this when *reading* the comment (`debug-id-upload.ts` uses `/^\s*\/\/# sourceMappingURL=(.*)$/m`), so this aligns the stripping side with it. Genuine comments sit on their own line and are stripped exactly as before; string-embedded text no longer matches. Excluding whitespace/quotes from the URL matches how browsers read the value (`data:` URIs still work) and blocks the template-literal variant of the same issue. The CSS regex gets the same line-start condition. Added 4 tests — two reproduce the truncation and fail on the old regex, two pin existing behavior. Would love to hear whether this approach makes sense. If you'd prefer a more minimal change, the URL charset restriction can be dropped — the line-start condition alone fixes the truncation. --------- Co-authored-by: Sigrid <32902192+s1gr1d@users.noreply.github.com>
- With the move off of dynamic sampling, the data from this DSN is now overrepresented - In order to reduce the telemetry collected, introduce a sample rate below 1 for the bunder plugins Co-authored-by: Sigrid <32902192+s1gr1d@users.noreply.github.com>
Unsupported MCP discovery requests such as `resources/list` currently inflate server failure rates. Classify JSON-RPC responses using the [OTel MCP server convention](https://github.com/open-telemetry/semantic-conventions-genai/blob/main/docs/gen-ai/mcp.md#server), recording the response code without marking caller errors as server failures. Tool results with `isError: true` now report `tool_error`; JSON-RPC payloads and transport options are unchanged. Keep MCP 2026-07-28 client/server metadata on the corresponding request span instead of caching it across requests on a reused transport. Legacy `initialize` session attribution remains supported. The OTel convention is still Development and excludes exactly `-32700`, `-32600`, `-32601`, `-32602`, and `-32002` from server errors. Newer MCP codes retain the convention's default error classification; changing that policy belongs in a separate follow-up. --------- Co-authored-by: GPT-6 (Codex) <noreply@openai.com> Co-authored-by: GPT-6 (Codex) <codex@openai.com>
Fixes missing MCP spans when a transport delivers queued requests during `server.connect()`. The MCP SDK installs its callbacks before calling `transport.start()`, so instrumentation must run at that boundary. The temporary interceptor restores `start()` before invoking it, preserving its receiver, Promise and synchronous errors. Transports without a patchable `start()` retain the post-connect fallback. Regression tests cover MCP v1 and v2 in ESM/CJS, including optional Sentry-managed OpenTelemetry setup. A deployed Worker A/B reproduced the missing spans without the fix; the modern protocol entry path was unaffected. This does not change OpenTelemetry providers, exporters or propagation. Fixes #23977 --------- Co-authored-by: OpenAI Codex <codex@openai.com>
`sentryRemixVitePlugin` now injects debug IDs and uploads source maps as part of the build. Options widen to `BuildTimeOptionsBase`; opt out with `sourcemaps.disable`. Deletion defaults to `./build/**/*.map` rather than `./**/*.map`, which the bundler plugin globs without ignoring `node_modules` before deleting with `force: true`. --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Asserts each client chunk carries exactly one debug ID and that the shipped IDs match the uploaded artifact bundles. Stacked on #24463. --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
…rewrite (#24499) The middleware wrapper treated every path under the tunnel route as a tunnel request, while the tunnel rewrite only serves the exact route with the org and project query params. Match tunnel requests the same way the rewrite does so the two stay consistent. Fixes JS-3719 Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
…s does (#24479) The attribute folded `back-forward` and `restore` into `navigate` and renamed `back-forward-cache` to `bfcache`, which is lossy in a direction nobody can undo server-side. I changed the mapping test to assert every web-vitals navigation type is reported verbatim on the attribute. On the product side, the filter will account for all these unfolded values.
…no (#24412) Deno's `nextLoad` reports no module format for a `.json` file, where Node reports `'json'`. With any load hook installed, Deno's CJS loader then compiles the JSON as JavaScript, so `require()` of it throws `SyntaxError: Unexpected token ':'`. A pass-through `Module.registerHooks({ resolve, load })` reproduces this with no Sentry code involved, on both Deno 2.8.3 and 2.9.6. That made `@sentry/deno/import` (as a first import or as a `--preload`) crash any app whose dependency graph requires JSON. `redis` and `ioredis` both do, through `@ioredis/commands`. Restoring the format in our load wrapper is enough. Node never reports a missing format, so the wrapper only applies on Deno. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Five Deno E2E apps become one. `deno-static`, `deno-mysql`, `deno-pg` and `deno-redis` are deleted, and CI goes from five required rows plus one optional to two required plus one optional. The split was accidental rather than designed. `deno-static` was a verbatim copy of `deno` taken before the span streaming port (#24002), one of twenty such copies from that rollout. `deno-mysql` and `deno-pg` were one route each, and carried an `import '@sentry/deno/import'` first-import rule that a comment tied to Deno 2.8.0 through 2.8.2. That rule is stale: the SDK now requires Deno >= 2.8.3 (#22790), and the README documents `--preload` (#24215). Nothing in E2E ran that documented setup. The consolidated app now starts with `deno run --preload=@sentry/deno/import`, so it needs no import ordering rule and no dynamic `import()`. `mysql`, `pg`, `redis` and `ioredis` are plain static imports, and one `docker-compose.yml` starts all three databases. The static trace lifecycle becomes a `sentryTest` variant of the same app, driven by `E2E_TEST_STATIC`, rather than a second copy. The six lifecycle-agnostic specs (errors, scope, context, breadcrumbs, logs, metrics) live once and run in both modes. Only the specs that assert envelope shape are split, into `tests/streamed/` and `tests/static/`, selected by `testIgnore`. `isSegmentFor` and the Redis span helpers, previously copied across four files, move into `tests/streamed/utils.ts`. Decisions: - `deno.json` maps `@sentry/deno/import` to the installed file rather than to `npm:@sentry/deno/import`. This app installs the SDK from a local tarball, which has no registry version for Deno to match a preloaded `npm:` specifier against. `--preload=npm:zod` works here, so the limitation is the tarball, not `--preload`. - The variant runs `pnpm test:build:static` / `pnpm test:assert:static` rather than an inline `E2E_TEST_STATIC=true` prefix. The local runner wraps the command in `volta run`, which reads a leading assignment as the executable name. `node-express`'s existing `E2E_TEST_OTEL_SETUP` variant has the same problem and is broken locally today; fixing `run.ts` is separate work. - The database specs stay streaming only, as they are today. There is no static database coverage to preserve, and writing it is separate work. - `docker compose up` stays in the start command. Playwright creates its web server tasks before global setup, so the app starts first. The three deleted apps all did the same. - The first-import form keeps its coverage in `deno-integration-tests` (`suites/orchestrion-{mysql,postgres}`). Their stale `TODO: revisit --preload once Deno 2.8.3 ships` comments are dropped. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
Three unrelated flakes, all of which pass locally and fail only under CI load. **Tests that time out loading the SDK** Several unit tests time out in CI on the first test in a file. The first dynamic import of a large SDK graph pays for transforming it, and that cost is charged to whichever test triggers it. Locally it is a few hundred milliseconds. On a loaded runner it crosses the 5000ms test timeout. Swept every unit test in the repo and fixed the files that show the pattern. Fixed with a bare side-effect `import` at the top of the file. Collection is not bounded by the test timeout, so pulling the load into it takes the cost off the test without changing what the test exercises. Exception: `nuxt vite/orchestrion` has to register its `vi.doMock` calls before the module under test loads, and a static import is hoisted above them, so it warms the graph from `beforeAll` instead. | file | before | after | | -------------------------------------- | -----: | ----: | | browser-utils inp | 594ms | 9ms | | browser-utils metricObserverOrdering | 409ms | 22ms | | nextjs appRouterRoutingInstrumentation | 750ms | 233ms | | nuxt vite/orchestrion | 536ms | 1ms | | sveltekit index.workerd | 625ms | 8ms | | tanstackstart-react client/tunnelRoute | 433ms | 1ms | Which file pays is not fixed: the two browser-utils files traded places between runs, because the transform lands on whichever test reaches the graph first. Three tests in these packages still run over 400ms, and all three are slow for a reason: - The two nextjs `appRouter` tests busy-wait 1100ms on purpose. - `conflictingDebugOptions` re-evaluates three SDK entry points for each `debug-build` mock, which no warmup can avoid. **INP span never sent** `hidePage` waits for one `requestIdleCallback` before hiding, assuming web-vitals has already queued its own idle callback and will therefore run first. But web-vitals only queues its callback once the click's Event Timing entry reaches its observer, which is after `hidePage` queues its own. So `hidePage` wins the race and hides the page too early. That loses the interaction. The forced report web-vitals does on `visibilitychange` runs while the metric is still -1, and the pending callback that sets the real value afterwards reports unforced. No INP is emitted at all and the test waits out its 30s timeout. Fixed by waiting for the entry and queuing the idle callback from a task after it, which puts web-vitals' callback first. Callers that never interacted skip the wait, so the 13 that only need the page hidden pay nothing. The react-router-6 e2e suite now passes 10/10 and drops from 1.4m to ~53s. **Cron job that never runs** Two bugs in `suites/cron/cron`, both reproducible under CPU load. `cron`'s `start()` sizes the delay to the next tick from two clock reads, clamps a negative result to -1, and then treats that -1 as "stop". A pause between the two reads that straddles a second boundary is enough. The job is left scheduled for nothing, and the scenario exits on its own 15s timer having sent nothing. That is the reported failure, which reads as `0/5 expected envelope(s)` on a clean exit 0 with no captured output. A probe measured that clamp firing 5 times in 613,775 calls under load and never on an idle machine. The scenario now starts the job again, which re-reads the clock away from the boundary, and throws if it still refuses, so a recurrence fails loudly instead of silently. Separately, each check-in is its own HTTP request, so the order they reach the mock server is not the order the SDK sent them in. Under load the `ok` check-in overtook `in_progress`. This is fallout from #20661, which moved these envelopes off stdout, where they were inherently ordered. The assertions are now `.unordered()`. Failed roughly 1 run in 30 under load before, pass 120/120 after. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…entry point (#24455) The webpack plugin still carried its webpack 4 era structure: a `sentryWebpackPluginFactory` that took `BannerPlugin`/`DefinePlugin` classes so the same code could serve webpack 4 and 5, a `require('webpack')` at module load to feed those fallbacks, and a separate `webpack5` entry point whose only difference was calling that factory without them. Webpack 4 hasn't been supported for a long time. The plugin now reads the classes from `compiler.webpack` only, so the factory and the fallback are gone. `compiler.webpack` was added in webpack 5.1.0, three days after 5.0.0, so the `webpack` peer dependency moves to `>=5.1.0`. With the fallback gone there is nothing left to distinguish `@sentry/bundler-plugins/webpack5` from `@sentry/bundler-plugins/webpack`, so the `webpack5` entry point is removed rather than deprecated. Both changes are documented in the v11 migration guide. --------- Co-authored-by: Tim Fish <tim@meaty.io> Co-authored-by: Charly Gomez <charly.gomez1310@gmail.com>
…24492) SAM starts EAGER runtime containers before binding its API endpoint. Those containers randomly choose ports in 5000–8999, so one can take our old port 7120. Its plain-text 404 passed the readiness check, then every Lambda invocation failed with a JSON-deserialization error, matching the reported CI failures. Move both AWS E2E apps to port 17120, outside that range. Require SAM's `PathNotFoundLocally` response header for readiness and pause between unsuccessful probes. All 10 layer tests passed with the old port deliberately occupied by a runtime container. Fixes #24465, fixes #24466, fixes #24467, fixes #24468, fixes #24469, fixes #24470, fixes #24471, fixes #24472, fixes #24473. Co-authored-by: GPT-6 <codex@openai.com>
…ter (#24456) Stacked on #24454. Adds an optional `gen-ai-libraries` e2e app that drives every gen-AI **library** we instrument — OpenAI, Anthropic, Mistral, Together and the Vercel AI SDK — against a real model through the single `E2E_OPENROUTER_API_KEY` the other AI e2e apps use, with one chat-query route and one forced-tool-call route each. `node-mistral` is folded in and removed; Mistral is now one of the covered libraries. ## Structure Shared, framework-agnostic handlers in `src/libraries.ts` are wired into two runtime entries, selected by a `RUNTIME` variant (`tests/constants.ts`), so both instrumentation paths get real-call coverage from one app: - **node** (default) — `src/entry.node.ts`, an express app with runtime channel injection preloaded via `node --import ./src/instrument.node.ts`. - **cloudflare** (`optionalVariants`, `RUNTIME=cloudflare`) — `src/entry.cloudflare.ts`, built with `vite` + `@sentry/cloudflare/vite` (build-time channel injection) and run on workerd via `wrangler dev` against the build's generated config (`dist/gen_ai_libraries/wrangler.json`). `playwright.config.ts` picks the start command and port per `RUNTIME`; the tests (`tests/chat.test.ts`, `tests/tools.test.ts`) are runtime-agnostic — they hit `baseURL` and assert the streamed gen_ai spans, parametrized over the library list in `tests/utils.ts`. ## Why these five Every call uses `openai/gpt-4o-mini`. OpenRouter serves an OpenAI-compatible `/api/v1/chat/completions` and an Anthropic-compatible `/api/v1/messages` ("Anthropic skin"), so all five SDKs reach it (Together/Mistral via lenient OpenAI-shape parsing, the Vercel AI SDK via `@openrouter/ai-sdk-provider`). The model is incidental; each SDK's own request/response code path is what's under test. Two instrumented libraries can't reach OpenRouter and are omitted with a code comment: **Google GenAI** (native Gemini `generateContent` format isn't served) and **Groq** (its SDK hardcodes a `/openai/v1` request path OpenRouter doesn't expose). Groq shares Together's OpenAI-compatible instrumentation code path — exercised here — and is covered by the node-integration-tests in the base PR. ## Notes - The node variant was verified end-to-end against real OpenRouter calls: all five libraries emit the expected gen_ai spans (`together_ai`, `anthropic`, `mistralai`, `openai`, plus the Vercel AI SDK's `gen_ai.generate_content`), including recorded tool calls. The Cloudflare variant runs the same suite in CI. - Folding in `node-mistral` drops its Mistral-specific stream-drain edge cases (tee/pipe, dataloader co-instrumentation) in favour of the uniform query+tool-call coverage across libraries. - The app is marked `optional`, so it only runs when the OpenRouter key is present. --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…red fetch headers (#24090) Three ways a sensitive value slipped past the denylist, now that cookies ship as one array attribute (#24231). A cookie segment without an `=` is a nameless cookie, so the bare token is its value (RFC 6265bis). The SDK treated it as a name, and no name-based denylist can match a value, so `Cookie: <session-token>` shipped the token in the clear. Such segments now become a `[Filtered]` array element. The `Cookie` header was also split on `"; "`, but the space is not guaranteed on the wire, so a cookie glued on with a bare `;` leaked inside the previous cookie's value. The split is now on `";"`. Headers listed in `headersToSpanAttributes` skipped the denylist entirely, so `authorization` went out in the clear. The spec says an allowlist never exempts a sensitive name, so those now emit `['[Filtered]']`. Fixes #24085 --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
…rs (#24476) Flue is registered, not patched — `instrument()` writes into module-scope state — so instrumenting it needs a reference to that module's own binding, and no channel payload carries one. A bundled worker has no `node_modules` to resolve one from, so this supplies it at build time. `@sentry/cloudflare/vite` splices a static `@flue/runtime` import into Sentry's own Flue integration module and exposes the namespace on `providedModules`; `flueIntegration()` reads it there and registers. A `registrationOnly` orchestrion entry installs the integration on a bundler-only SDK and keeps it reachable under `sideEffects: false`. `@flue/runtime` is ESM-only, so the presence check resolves with `createRequire` from the Vite root and counts `ERR_PACKAGE_PATH_NOT_EXPORTED` as a hit — the package publishes no `require` condition on any subpath, while a genuinely missing one reports `MODULE_NOT_FOUND`. The namespace is exposed through a getter rather than assigned, because the bundler may evaluate Sentry's module before `@flue/runtime` is initialized. An app that also calls `instrument()` itself is unaffected: its own registration wins, and only the resulting `InstrumentationAlreadyInstalledError` is swallowed. On Node registering stays a manual `instrument(Sentry.createFlueInstrumentation())` call — `flueIntegration()` is not among the default integrations there. Verified end to end in #24477. --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Before submitting a pull request, please take a look at our [Contributing](https://github.com/getsentry/sentry-javascript/blob/master/CONTRIBUTING.md) guidelines and verify: - [x] If you've added code that should be tested, please add tests. - [x] Ensure your code lints and the test suite passes (`yarn lint`) & (`yarn test`). - [x] Link an issue if there is one related to your pull request. If no issue is linked, one will be auto-generated and linked. Closes #24047 ### Problem `@sentry/bun`'s `_init` spreads the user options and then unconditionally overwrites `runtime` with `{ name: 'bun', version: ... }`. `@sentry/elysia` correctly computes `runtime: getRuntime()` (→ `node` off Bun) and passes it down, but the Bun SDK discards it, so every Elysia-on-Node event is attributed to `{ name: 'bun', version: 'unknown' }`. This is the same bug that #19269 fixed one layer up in `NodeClient` (`runtime: options.runtime || { name: 'node', ... }`). ### Fix - `packages/bun/src/sdk.ts`: only default `runtime` when the caller did not supply one. - `packages/bun/src/types.ts`: add the (hidden) `runtime` option to `BaseBunOptions`, mirroring `BaseNodeOptions`, so the above type-checks (Elysia's `ElysiaOptions` is an alias of `BunOptions`). ### Tests - `packages/bun/test/init.test.ts`: `runtime` block — asserts the default is `{ name: 'bun', version: Bun.version }` and that a caller-supplied `runtime` is respected. The second test fails on `develop` (`{ name: 'bun', version: '1.4.2' }` received) and passes with the fix. - `packages/elysia/test/sdk.test.ts`: added the Bun-side counterpart of the existing `detects runtime correctly` test (stubs the `Bun` global) so both runtimes are asserted at the Elysia layer too. Verified locally: `bun test` in `packages/bun` (64 pass, 0 fail), `vitest run` in `packages/elysia` (9 pass), `yarn build:types` + `yarn lint` in `packages/bun`, `oxfmt --check` on the touched files.
This PR removes the `{ reason: 'buffer_overflow', category: 'log_item'
}` client report the SDK sent when the breadcrumbs buffer (100
breadcrumbs limit) overflowed and we evicted breadcrumbs.
Why? When we started working on logs, we [wanted to
know](getsentry/team-sdks#116) how many
breadcrumbs we currently discard due to the 100 crumbs limit. We used
the new `log_item` data category for this and `buffer_overflow` reason.
Later on, we added client reports for actual log discards and re-used
this data category but sent different reasons. Meaning different
telemtry items now fall into the same discard bucket as reported in
#24510.
Since I don't think we still need to know about breadcrumb discards, and
they're not their own telemetry items but part of errror and transaction
events, I think we can just stop emitting client reports for them.
closes #24510
closes #23888 The orchestrion gate that the comment described was removed on purpose when the bun auto-instrumentation handling was streamlined. The tracing integrations are now always added when spans are enabled, and the channel-based ones do nothing without the bun plugin. got stale with #23392 Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Overlooked a change #24542 (comment)
Ember pageload and navigation spans lack the route ID used to infer their descriptions. Add `router.navigation.route.id` with the framework's route name when available. Omit it for missing or empty names so delayed updates preserve caller-provided metadata. Fixes #24284. --------- Co-authored-by: GPT-6 <codex@openai.com>
…24539) eve 0.62/0.63 changed its instrumentation contract in two ways that broke the `node-eve` e2e app and made gen_ai content capture awkward: a flat `agent/instrumentation.ts` is no longer discovered (it must live under `agent/instrumentation/<provider>.ts` and export `defineInstrumentation(...)`), and eve now stamps every AI SDK call with `recordInputs`/`recordOutputs: false`. That per-call flag on the `ai:telemetry` channel outranks the global `dataCollection.genAI` setting, so gen_ai message content was silently dropped — the only escape was setting `recordInputs`/`recordOutputs` per integration, which is poor DX. This adds two APIs in `@sentry/server-utils`, re-exported from the runtime packages: - **`eveIntegration()`** — marks the client so the Vercel AI channel subscriber records gen_ai inputs/outputs by default under eve. An explicit `dataCollection.genAI` or `vercelAIIntegration({ recordInputs })` still take precedence. - **`Sentry.eveInstrumentation(options)`** (in `@sentry/node`) — an all-in-one provider for a single `agent/instrumentation/*.ts` file. It runs `Sentry.init` (adding `eveIntegration`) at server startup and tags each turn's AI spans with the eve session id as the Sentry conversation id via `turn.started` / `step.attempt.started` events, replacing the separate `eveConversationHook` file. Accepts `getConversationId` to customize the id. The `node-eve` e2e app is migrated to eve `^0.63.0` and the new single-file setup. ## New Usage ```ts // agent/instrumentation/sentry.ts import * as Sentry from '@sentry/node'; import { defineInstrumentation } from 'eve/instrumentation'; export default defineInstrumentation( Sentry.eveInstrumentation({ dsn: process.env.E2E_TEST_DSN, tracesSampleRate: 1.0, }), ); ``` --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: Jan Peer Stöcklmair <jan.oster94@gmail.com>
s1gr1d
requested review from
JPeer264,
Lms24,
chargome,
isaacs,
logaretm and
nicohrubec
and removed request for
a team
September 21, 2026 13:59
Contributor
size-limit report 📦
|
Lms24
approved these changes
Sep 21, 2026
JPeer264
approved these changes
Sep 21, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.