Repository navigation
meta(changelog): Update changelog for 11.5.0 - #25125
Conversation
[Gitflow] Merge master into develop
…amework (#24598) POC for running one framework e2e app on several server runtimes instead of one app per runtime (Linear project P-JS-2537). `react-router-8-framework` now runs its full Playwright suite on Bun, Deno and Cloudflare (local workerd) as optional variants, next to the Node job. Each runtime inits its own SDK, the way a user of that runtime would: Node `@sentry/react-router`, Bun `@sentry/bun`, Deno `@sentry/deno` (with `--preload=@sentry/deno/import`) and Cloudflare `@sentry/cloudflare`. `@sentry/react-router` then only provides the framework wrappers, so values from its `init()` (`sdk.name`, the `runtime` tag, the `/__manifest` filter) are Node-only, and the tests branch on that. Using the runtime SDKs is what makes the Bun variant work: `@sentry/node` creates no `http.server` span on Bun, `@sentry/bun` does. A variant declares its runtime with a `runtime` field instead of the label. From it, both e2e jobs install Bun or Deno, the runner and CI set `RUNTIME` for the build and the assert command (read with the new `getRuntime()` from `@sentry-internal/test-utils`, and `playwright.config.mjs` picks the start command from it), and the runner copies the files named for that runtime over their base files in the temporary copy of the app. So the Cloudflare build gets `vite.cloudflare.config.ts` (`@cloudflare/vite-plugin` + `sentryCloudflareVitePlugin`) and `entry.server.cloudflare.tsx`, while Bun and Deno reuse the Node build. React Router has no option to pick a server entry, and this way a variant needs no framework or bundler config and no `build.yml` change. The Bun and Deno variants of `hono-4` and `hono-4-legacy` set `runtime` too, because CI no longer reads the runtime from the label. The convention is in the e2e README. Other expected differences: Express is not instrumented under `bun run` and there is no Express layer on workerd, so there the error transaction stays the request path and the meta tag names the `http.server` span. Deno is pinned to v2.9.0, because Deno 2.8 loses async context in socket callbacks and drops `ioredis` spans. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Exercise Bun request-body capture with default span streaming, preserving the existing metadata, truncation, disabled-capture, and handler-body assertions. The body is available on the streamed segment as `http.request.body.data`, so this suite no longer needs a static lifecycle pin. Static transaction coverage remains in `elysia-bun-static`. Fixes #24134 --------- Co-authored-by: GPT-6 <codex@openai.com>
…span streaming (#25020) Move rejection, feature-flag, GrowthBook, and client-report coverage to the default span-streaming lifecycle. Preserve existing assertions while adapting transaction checks to streamed spans and allowing span/error envelopes to arrive in either order. Part of #24141 (JS-3611) --------- Co-authored-by: GPT-6 <codex@openai.com>
Move AWS integration coverage to the default span-streaming lifecycle and fold the streamed twin into the original suite. Preserve the existing assertions and both SDK-version variants in ESM and CJS, collecting spans across envelopes before asserting. Part of #24141 (JS-3611). Co-authored-by: GPT-6 <codex@openai.com>
…er-8-framework (#24599) part of #24836 With the Cloudflare variant of `react-router-8-framework`, the separate `react-router-8-cloudflare` app only added its MySQL test. This moves the MySQL route and both tests into `react-router-8-framework` and removes the old app, so one app covers React Router on Node, Bun, Deno and Cloudflare. The MySQL tests now run on every variant, not only on Cloudflare. The Worker is wrapped by `sentryCloudflareVitePlugin` instead of a manual `withSentry` call; other Cloudflare apps still cover manual `withSentry`. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Uses `SENTRY_OP` from `@sentry/conventions/attributes` throughout SDK instrumentation and tests. It is an exact replacement for `sentry.op`; emitted values, attribute precedence, and serialization remain unchanged. Deprecates the existing core constant while preserving its public export and SDK re-exports for backward compatibility. Part of #24961 / [JS-3868](https://linear.app/getsentry/issue/JS-3868). --------- Co-authored-by: GPT-6 <codex@openai.com>
…25033) ## What Workers AI calls now become `evaluate` spans only when the model ID starts with `typesafe/jev`, not when the input has `state` and `questions`. ## Why The input shape is a loose signal: any other model with those fields was traced as an evaluation. Jev is an evaluation model, so its model ID is exact, and other TypeSafe models stay unaffected. Follow-up to #24833. --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Ports the remaining `astro-5-cf-workers` E2E app to default span streaming. `astro-7-static` retains the group's static lifecycle coverage. The server config is intentionally empty so Astro does not inject its default Node SDK initialization. The Cloudflare wrapper already initializes Sentry from Wrangler bindings, reinitializing during the first page load dropped that request's streamed span. Fixes #23809 --------- Co-authored-by: GPT-6 <codex@openai.com>
Run filesystem instrumentation tests with the default span-streaming lifecycle. Preserve the existing path, error, and recording-option assertions while adapting them to streamed span fields. Each test asserts its request's span container directly. Closes #24141 (JS-3611) --------- Co-authored-by: GPT-6 <codex@openai.com>
Uses `SENTRY_ORIGIN` from `@sentry/conventions/attributes` in the browser SDK, browser framework integrations, and their tests. It has the same `sentry.origin` value; transmitted data and public exports are unchanged. Part of #24961 / [JS-3868](https://linear.app/getsentry/issue/JS-3868). Co-authored-by: GPT-6 <codex@openai.com>
…24983) Uses `SENTRY_ORIGIN` from `@sentry/conventions/attributes` in core, browser-utils, OpenTelemetry tests, and Effect tracing/logging. It has the same `sentry.origin` value; transmitted data and public exports are unchanged. Part of #24961 / [JS-3868](https://linear.app/getsentry/issue/JS-3868). Co-authored-by: GPT-6 <codex@openai.com>
## What Adds an e2e test to the eve app. The test makes an agent tool call a TypeSafe Jev evaluation. ## Why Make sure a Jev evaluation in an eve tool records a `gen_ai.evaluate` span under the tool span. --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Uses `SENTRY_ORIGIN` from `@sentry/conventions/attributes` in full-stack framework integrations and their tests. It has the same `sentry.origin` value; transmitted data and public exports are unchanged. Nuxt’s private database-origin constant is renamed to avoid an import collision; its value remains `auto.db.nuxt`. Part of #24961 / [JS-3868](https://linear.app/getsentry/issue/JS-3868). Co-authored-by: GPT-6 <codex@openai.com>
Uses `SENTRY_ORIGIN` from `@sentry/conventions/attributes` in server instrumentation, runtimes, and their tests. It has the same `sentry.origin` value; transmitted data and public exports are unchanged. Part of #24961 / [JS-3868](https://linear.app/getsentry/issue/JS-3868). Co-authored-by: GPT-6 <codex@openai.com>
…mming (#25040) Fix screenshot annotations starting at the wrong position when a drag begins inside an existing box, and prevent the background from getting darker while dragging. Mouse-down now uses image-relative coordinates consistently, and highlight shadows no longer leak into the next canvas repaint. reported here: https://sentry.slack.com/archives/CDXAKMGTU/p1790972462069039 Before/after from a local reproduction with generated sample content. Both captures show the same drag with the mouse held down; red markers indicate its start and cursor positions. | Before | After | | --- | --- | |  |  | --------- Co-authored-by: OpenAI Codex <codex@openai.com>
Marks `SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN` as deprecated in favor of `SENTRY_ORIGIN` from `@sentry/conventions/attributes`. This PR finalizes the replacement of all SDK constants that are available in the conventions package. Fixes #24961 / [JS-3868](https://linear.app/getsentry/issue/JS-3868). Co-authored-by: GPT-6 <codex@openai.com>
Adds `code.file.path` to `cache.put` spans, so `use cache` spans show
which function they belong to.
The cache key contains the function id. Next.js' server-reference
manifest maps it to the source file. Keys come in two forms:
- JSON: `["buildId","c0a941ad…",[args]]` (start with `[`)
- multipart, when args don't serialize to JSON (`params`, `children`):
`1:069:["buildId","c0a941ad…",[…]]1:1c:{"id":"123"}` (length-prefixed
fields)
Logged real-world data to use this in the unit tests (from 16.3 and
canary version).
Linear:
https://linear.app/getsentry/issue/JSSDK-31/add-cache-source-file-to-trace-back-where-the-cache-was-created
…n Firefox (#25024) Replay calls our `setTimeout` from `@sentry/browser-utils`. When `window.setTimeout` is wrapped (by default it is, by our own `browserApiErrors` integration), that `setTimeout` comes from a sandbox iframe that is removed right away. In rare cases Firefox throws `NS_ERROR_NOT_INITIALIZED` when it is called, which shows up as an unhandled rejection from Replay's `afterSendEvent` handler. This catches the error, falls back to `window.setTimeout` and caches it. --------- Co-authored-by: Sergiy Dybskiy <sergical@users.noreply.github.com> Co-authored-by: sentry[bot] <39604003+sentry[bot]@users.noreply.github.com> Co-authored-by: Lukas Stracke <lukas.stracke@sentry.io> Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…24985) Next.js removes the `basePath` from `req.url` before running Pages Router data fetchers and API routes. So errors captured there reported a `request.url` without it, for example `http://localhost:3000/foo/bar` instead of `http://localhost:3000/base/foo/bar`. Next keeps the URL as it was originally requested in its internal request meta (`initURL`), set before the `basePath` is removed. We now take the path and query from there. The origin still comes from the request headers, because Next builds the absolute `initURL` from its own hostname and port, which can differ from the public host behind a proxy. API routes were affected the same way, so they're covered too. Fixes #24975 --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
follow up from #23760 (comment) Remove the unconditional warning when `beforeSendSpan` returns `null`, saving ~90B (compressed) / ~200B (uncompressed). The type already disallows returning null since v9. Keeps the runtime fallback to the original span for JavaScript callers, with one regression test covering the shared behavior. Co-authored-by: GPT-6 <codex@openai.com>
Port the AWS serverless GraphQL integration test to default span streaming. Preserve startup and operation span checks, including the operation name, successful status, and instrumentation origin. Part of #24139 --------- Co-authored-by: GPT-6 <codex@openai.com>
…gy (#24995) `withSentry`, Durable Objects, Workflows and `WorkerEntrypoint` install the AsyncLocalStorage async context strategy. When an OpenTelemetry strategy is already installed, the new strategy reuses its `AsyncLocalStorage` but stores Sentry scopes in it. The OpenTelemetry context manager then reads a scope store as a context, and every later request fails with `context.getValue is not a function` (#24603). They now keep an installed OpenTelemetry strategy. This is needed for `@sentry/nextjs/cloudflare`, which installs the OpenTelemetry strategy before it calls `withSentry`, and for apps whose `register()` runs before the Worker entry. The check uses `withActiveSpan`, which only the OpenTelemetry strategy has, so no new marker is needed. The Pages plugin is unchanged. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Reuse the existing `isObjectLike` helper for repeated non-null object guards across SDK packages. It checks the same runtime condition and narrows unknown values, allowing redundant type assertions to be removed without changing behavior. Co-authored-by: OpenAI Codex <codex@openai.com>
…25061) The public types of `@sentry/sveltekit` include `consoleLoggingIntegration` from the Node entry. But the worker entry, which Cloudflare selects through the `worker` and `workerd` conditions, did not re-export it from `@sentry/cloudflare`. So `Sentry.consoleLoggingIntegration()` was `undefined` on Workers. This adds only that one export. Other Node-typed exports are also missing from the worker entry. We will handle them with a dedicated Cloudflare entry point, which can also fix the types (#24841). Fixes #24965 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Embroider published new patch versions of vite, macros, core and compat today with almost no files in the tarballs, which broke every ember e2e app, fixed by overriding just those versions back to the previous ones in the test apps. The overrides are scoped to the broken versions, so they stop applying once a fixed release is out and can be removed then.
We were on web-vitals 6.1.1, so I bumped it to the latest 6.2.3 to pick up the upstream fixes. **Changelog** - Fixes an INP clean-up memory leak and caps pending LoAFs to avoid another leak ([#799](GoogleChrome/web-vitals#799), [#796](GoogleChrome/web-vitals#796)) - Fixes negative `resourceLoadDuration` in LCP attribution and negative `inputDelay` in INP attribution ([#803](GoogleChrome/web-vitals#803), [#789](GoogleChrome/web-vitals#789)) - Stops a spurious CLS report of 0 after a bfcache restore ([#786](GoogleChrome/web-vitals#786)) - Guards `supportedEntryTypes` for older browsers ([#787](GoogleChrome/web-vitals#787))
… on gen_ai spans (#24721) v10 got `vercel.ai.telemetry.metadata.<key>` attributes from the AI SDK's own OTel spans. In v11, `ai` 4 to 6 go through the orchestrion subscriber, which never read `metadata`, so v11 dropped it. The orchestrion subscriber now passes the metadata to the channel subscriber, which sets it as span attributes when each span starts. The `invoke_agent`, `generate_content` and `embeddings` spans get the attributes, and `execute_tool` spans don't. This matches the AI SDK, which leaves metadata off its `ai.toolCall` spans. Values are cast to string, as discussed in the linked sentry-conventions PR. If this causes a problem we can revisit, but all extant examples found in the wild are strings already, so it is likely safe, and extremely cheap. fixes JS-3800 fixes #24720 Re: #24706 Re: getsentry/sentry-conventions#662 Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
) On Vercel, a function can be suspended as soon as it sends the response. Telemetry that is still buffered (spans, logs, metrics, errors) then arrives late or never. When a response finishes, `@sentry/node` now uses `waitUntil` to keep the function alive. It waits until the response closes and the request's root span ends (2 s max), then flushes. It works with or without tracing. Some frameworks end the root span shortly after the response closes, so the flush waits for it. Tested with unit tests and an integration test that fails without the change, and confirmed on a Vercel deployment. Closes #24909 Refs #23087 --------- Co-authored-by: Claude <claude@anthropic.com>
This PR adds the external contributor to the CHANGELOG.md file, so that they are credited for their contribution. See #25025 Co-authored-by: JPeer264 <10677263+JPeer264@users.noreply.github.com>
…AI conversation option (#24979) The Vercel AI integration filled `gen_ai.conversation.id` with `providerMetadata.openai.responseId`. That is the id of the response that just came back, so every call got a different value under a grouping attribute and showed up as its own one-span conversation. The same value is already on `gen_ai.response.id`. The mapping came in with #16992 and #19903 later had to guard it from overwriting user-set ids. The id now comes from `providerOptions.openai.conversation` (or `azure`), the Conversations API `conv_` id, which is the same on every turn. Child model-call and tool spans inherit it from the active operation span. `Sentry.setConversationId()` still wins, since `conversationIdIntegration` writes the scope value on `spanStart` after these start attributes. The v6 adapter forwards `providerOptions` so `ai` 4 to 6 behave the same. Not in this PR: reading the id from `runtimeContext` / `experimental_telemetry.metadata` goes with #24706 once #24721 lands. Part of #24832 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
…#24831) The LangChain integration only set `gen_ai.conversation.id` when the user called `Sentry.setConversationId()` themselves. LangGraph read `configurable.thread_id`, but stamped it on its own `invoke_agent` span only, so the chat and tool child spans went out without it. Child runs inherit their parent's metadata, so this PR reads the conversation id from run metadata and sets the attribute on the chat, chain and tool spans. On `@langchain/core` 0.1.20 to 1.1.39, `ensureConfig` copies every primitive `config.configurable` entry into that metadata, so an id passed to `invoke()` is already there. `@langchain/core` 1.1.40 stopped doing that for any handler except LangSmith's tracer. So where we inject our handler, in the chat-model hook and the LangGraph `invoke` proxy, we copy the three keys below from `configurable` into `metadata` ourselves. Metadata the user set takes precedence. Keys read, in order: - `thread_id`, the LangGraph checkpointer key and one of the two keys LangSmith groups threads by - `session_id`, the other LangSmith key - `sessionId`, what `RunnableWithMessageHistory` requires in JS An id set on the scope via `Sentry.setConversationId()` still wins. `conversationIdIntegration` applies it on `spanStart`, after the initial attributes, so an explicit user id overwrites the derived one. The integration test covers this. LangGraph's `invoke_agent` span and the tool spans `createReactAgent` creates now use the same helper. So they read the same keys, accept numeric ids, and let an id from `Sentry.setConversationId()` win over `thread_id`. Before, `thread_id` overwrote the scope id on the `invoke_agent` span only, and the tool spans never picked up `thread_id`. One gap remains on `@langchain/core` >= 1.1.40. If you pass `createLangChainCallbackHandler()` yourself to a chain outside LangGraph, the chain and tool spans get no id from `configurable`, because the handler never sees it. The chat spans still get it. Closing that would mean hooking more than chat models, so it is left for a follow-up. **Bun.** The new suite failed on the Bun runner because `@sentry/bun` builds its own default integration list and never registered `conversationIdIntegration`, so `Sentry.setConversationId()` was a no-op there. The second commit adds it, in the same position Node uses. Part of #24832. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
The release API rejects a release without a project, and the project given to the `sentry` SDK does not reach `release.create`. Since the move to that SDK (#23398), `sentry-upload-sourcemaps` failed with `400 Bad Request` on every run. The unit test mocked the SDK, so it did not catch it. Reproduced against a real org. Both upload scripts take the project from `--project`, then `SENTRY_PROJECT`, and fail with a clear message when neither is set. `@sentry/bundler-plugins` already did this. The React Router Vite plugin has the same bug, fixed separately. Fixes #24989 --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
The release API rejects a release without a project, and the project given to the `sentry` SDK does not reach `release.create`. Since the move to that SDK (#23398), the Vite plugin logged `[Sentry] Could not create release` on every build; the upload itself still ran, so builds succeeded without a release. The unit test mocked the SDK, so it did not catch it. The plugin now passes the project it already has, as `@sentry/bundler-plugins` does. Same bug in the Remix upload scripts, fixed in #25079. Refs #24989 Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Cloudflare documents Clef (`@cf/cloudflare/clef`) as a drop-in for Jev with the same `state` + `questions` request shape, so it already goes through the `evaluate` path from #24833. Only Jev had tests, so this adds a Clef integration test and a real-Worker E2E test. The integration mock returns the documented Clef response, which has no `{ state, result }` wrapper (the Jev binding response has one). That makes it cover the unwrapped branch of the evaluate response handling, which the Jev test does not reach. The E2E test calls the real model, so it is the one that confirms what the binding actually returns. The docs do not give a `model` value for the response, so it only asserts that it contains `clef`. Fixes #25011 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…25088) Next.js 16.4 canary drops the `authInterrupts` flag, so `forbidden()`/`unauthorized()` throws (`NEXT_HTTP_ERROR_FALLBACK;403`/`;401`) now need to be treated as control flow like `notFound()`. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…25117) Next.js 16.4 Turbopack now lists route handler `use cache` functions in the server-reference manifest, so `code.file.path` is set on `cache.put` spans for both bundlers. This drops the webpack-only expectation in both cacheComponents E2E apps, which started failing once CI resolved `next@^16` to 16.4.0. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…#25118) `@opennextjs/cloudflare` throws on the new `preview-props.json` manifest that Next.js 16.4 loads, so every request in the `(latest)` variant returns a 500 (opennextjs/opennextjs-cloudflare#1355). This pins the variant to 16.3 until the upstream fix (opennextjs/opennextjs-cloudflare#1356) is released, and we should switch it back to `next@latest` then. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Cached-token usage was inconsistent across AI integrations: Anthropic reported only uncached input tokens, some integrations dropped cache breakdowns, and LangChain could overwrite complete usage with counters from the final stream chunk. This produced incomplete totals and could leave cache counts greater than the reported input count, breaking downstream pricing. This PR treats input and output counts as inclusive totals. Cache reads and writes are subsets of input, and reasoning tokens are a subset of output. Provider-specific normalization happens before setting those attributes, so the breakdowns are never added to an already-inclusive total. - **Anthropic:** Include cache reads and writes in input usage and emit both breakdown attributes for regular and streaming responses. - **OpenAI:** Preserve cache details from Chat Completions and Responses usage without increasing their existing totals. - **Google GenAI:** Preserve cached-input usage and include thinking tokens in output, with reasoning reported separately. - **LangChain:** Prefer normalized message usage over generic `tokenUsage`, which can contain only the final stream chunk’s counters. Normalize raw Anthropic usage as a fallback and count shared candidate usage once per prompt. - **LangGraph:** Aggregate cache breakdowns alongside token totals for newly generated messages, excluding conversation history. Regression coverage includes competing usage sources, repeated streaming events, missing and zero cache counts, batched prompts, and shared candidate usage. Fixes #25069 --------- Co-authored-by: GPT-6 <codex@openai.com> Co-authored-by: Andrei <168741329+andreiborza@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
size-limit report 📦
|
| process.on('SIGTERM', async () => { | ||
| // We have 500ms for processing here, so we try to make sure to have enough time to send the events | ||
| await client.flush(200); |
There was a problem hiding this comment.
Bug: Calling init() multiple times registers duplicate SIGTERM and diagnostic channel handlers in setupVercelKeepAlive, causing resource leaks and redundant processing on each server response.
Severity: MEDIUM
Suggested Fix
Add a guard within setupVercelKeepAlive to ensure its logic only executes once per process. A simple boolean flag can be used to track if the setup has already been performed. This will prevent the accumulation of handlers on subsequent calls to init().
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/node/src/sdk/vercel.ts#L28-L30
Potential issue: The `setupVercelKeepAlive` function is called unconditionally every
time `init()` is invoked. This function registers a `SIGTERM` handler and subscribes to
the `HTTP_ON_SERVER_RESPONSE_FINISH` diagnostics channel. Because there is no guard to
prevent re-registration, multiple calls to `init()` will cause an accumulation of these
handlers. This results in redundant `client.flush()` operations on process termination
and duplicate processing for each HTTP response, leading to a resource leak and
potential performance degradation, especially in scenarios with hot module replacement
or complex initialization paths.
Did we get this right? 👍 / 👎 to inform future reviews.
There was a problem hiding this comment.
will check if this is actually an issue

No description provided.