Repository navigation
meta(changelog): Update changelog for 11.6.0 - #25184
Conversation
makes the `no-unsafe-random-apis` rule a bit more robust. We now catch: - `crypto.randomUUID!()` and TS casts (`as`, `satisfies`,` <T>`) - Optional calls: `performance?.now()`, `crypto?.randomUUID?.()` - Calls through a global object: `globalThis.performance.now()`, `GLOBAL_OBJ.crypto.randomUUID()`, `WINDOW.performance?.now()` --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
[Gitflow] Merge master into develop
Add Node runner equivalents of Cloudflare’s `collectStreamedSpans` and `collectStreamedSpansUntilSegment` so tests can collect across envelopes. Migrate AWS, feature-flag, GrowthBook, and sampler fallback tests using the segment helper. Part of #24141 --------- Co-authored-by: GPT-6 <codex@openai.com>
Port the OpenAI v5/v6/v7, Azure and tool-call integration tests to the default span-streaming lifecycle. I know this looks huge but it really isn't. This just uses the new `collectStreamedSpansUntilSegment` helper and that changes indentation that's why the diff is so large mostly. Part of #24138 --------- Co-authored-by: GPT-6 <codex@openai.com>
Run the Bedrock Converse and InvokeModel integration test with default span streaming. Also replaces some consts with conventions equivalents. Part of #24138 --------- Co-authored-by: GPT-6 <codex@openai.com>
Port the Anthropic integration suites to default span streaming. Remove the redundant streaming-only test and duplicate initialization files; no static coverage is added. Part of #24138 --------- Co-authored-by: GPT-6 <codex@openai.com>
Port LangGraph integration tests to default span streaming and remove the redundant streaming-only case. Part of #24138 --------- Co-authored-by: GPT-6 <codex@openai.com>
Port Google GenAI v1 and v2 integration tests to default span streaming. Fold the redundant streaming-only case into the PII test and remove its initialization file. No static coverage is added. Part of #24138 --------- Co-authored-by: GPT-6 <codex@openai.com>
Port the LangChain integration suites to default span streaming. Fold the streaming-only and duplicate count-only cases into the retained tests, without adding static coverage. Part of #24138 --------- Co-authored-by: GPT-6 <codex@openai.com>
Port the Mastra integration suites to default span streaming. Part of #24138 --------- Co-authored-by: GPT-6 <codex@openai.com>
…on state (#23315) `instrumentLangGraph` recorded span input and output only when the graph state uses `MessagesAnnotation`. The input read did `args[0].messages ?? []` and the output helper returned early when `result.messages` was not an array, so a graph on a custom state annotation produced an empty `gen_ai.input.messages` and no `gen_ai.response.text`. No error, just an empty `invoke_agent` span in the AI Agents view. This keeps the `MessagesAnnotation` path unchanged. When there is no `messages` array, it serializes the whole input and output state and records it, wrapped as a single `{ role, content }` message so the attribute stays a valid chat array (the convention `extractLLMRequestAttributes` already uses in this package). A null input (the resume case) records nothing rather than a misleading empty array. Serialization uses core's circular-safe `stringify` so an unusual state object cannot throw inside the span callback. Fixes #19628 AI assistance (Claude, Anthropic) was used in developing this change. The design, review and verification were done by the author. Verified locally: the `@sentry/server-utils` vitest suite (335 to 339 passing), the new tests failing before and passing after the fix, `oxlint --type-aware`, `oxfmt --check`, `tsc` on the changed files, plus a real Google Gemini LangGraph run showing the span input and output empty before and populated after. --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: Abdelrahman Awad <abdelrahman.awad@sentry.io> Co-authored-by: Andrei Borza <andrei.borza@sentry.io>
…ation tests (#24925) `cache-client > cacheClient: true - dedupe drops the same error across invocations` failed on CI on its very first request: wrangler had reported "Ready", but the request still got 500s for the whole ~5s retry budget in `fetchWithRetry`. wrangler printed no error for it, so it's the known "ready but not serving yet" startup race (#20994, #22083), not a failure in the worker. This widens the budget to ~15s. Requests that are expected to fail already disable retries, so the only cost is that a genuinely unexpected 500 takes longer to report, which is fine within the 60s test timeout. The "expected to succeed" error now also includes the response body: CI never showed what the 500 actually was, and this makes the next occurrence diagnosable instead of us widening the window again blindly. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This PR adds the external contributor to the CHANGELOG.md file, so that they are credited for their contribution. See #23315 Co-authored-by: andreiborza <168741329+andreiborza@users.noreply.github.com>
This PR fixes* clock drift that occurs when devices go to sleep. After devices sleep for a few seconds, the browser's monotonic clock (accessed via `performance.now()`) stops counting. Once the sleep stops, the monotonic clock resumes right where it left off before the sleep, causing significant discrepancies between the actual time (wall clock) and the browser's monotonic clock time. Or in other words, there are two ways to get an absolute timestamp: - Using the monotonic clock via `peformance.timeOrigin + performance.now()` - has high, sub-millisecond precision and a guarantee that there are no time jumps or adjustments. But suffers from the sleep problem described above - Using the wall clock via `Date.now()` - lower millisecond precision, is known to be corrected (NTP or via users) and can even cause back jumps. But no sleep problem. With this fix, we make the following adjustments, to kinda get the best of both worlds: - Every `timestampInSecondsCall` checks the monotonic against the wall clock. If a threshold of difference is enocuntered, it corrects the `timeOrigin` so that we can keep using the precise monotonic clock, but anchor its relative time to a corrected time origin. - On every time origin correction, we remember the previous origin (up to 30 corrections). Needed for performance entries - Makes `browserPerformanceTimeOrigin` a time origin corrected helper function, where you pass in a relative time that comes from monotonic clock relative timestamps and it returns the time origin that was most accurate at that relative time point. - All spans and other telemetry we create from browsers `PerformanceEntry` objects carry relative times which are completely sleep-drift uncorrected. We use `browserPerformanceTimeOrigin` to return a corrected time stamp so that we can create an absolute timestamp and bring the performance entries to their respective actual time. ### FAQ If you think this sounds complicated, I agree. So let me answer the most obvious questions, because I asked myself these a lot, too: **Why not just always use `Date.now()` and avoid the complicated click drift detection and correction logic?** The main issue with this is that we still need to rely on relative monotonic clock timestamps for performance entries. We cannot correct them just with `Date.now()` alone but we still need to anchor them. So either we rely on the original `window.timeOrigin` and therefore have all performance entry telemetry happen much "earlier" than its surrounding telemetry relying on `Date.now()`, or we keep the time origin correction logic. But even in the second case (where we already pay the tax for drift detection and correction), telemetry would still have two different anchors: `Date.now()` for regular telemetry and the corrected time origin + monotonic time for performance entry telemetry. Another reason is that the monotonic clock gives us sun-millisecond precision while the wall clock stops at a millisecond resolution. **Why the reduction from a drift detection threshold of 5 minutes to just one second?** Because we keep everything centered around detection and origin offset correction, these timestamps need to be as accurate as possible. On phones, short frequent sleeps are very likely to happen. A lot of sleeps can accumulate until that 5 minutes threshold is reached. So it's really important we make these timestamps as accurate as possible. Fwiw, I reproduced this locally and the drift is already noticeable after just a few seconds of sleep. The 5 minutes threshold was arguably far too big beforehand. **Is there precedence for all of this stuff?** Somewhat, but I'd argue we're doing a bit more: OTel uses a mixture of `Date.now()` and `performance.now`: - Spans start at `Date.now()` and at start time, they record a `performance.now()` timestamp. On span end, they also take `performance.now()`, compute the diff and convert that to an end timestamp based on the start timestamp + diff. This is neat because it guarantees monotony in span durations. I stole this in #24903 In other places, OTel relies purely on Date.now(), and for performance entries, they simply take uncorrected timestamps. So our fix is more complete. \* **So... we're good now?** Well, not perfectly and we never will. With this choice we make another commitment (which we already did previously in less obvious cases) to `Date.now()`. This value can drift as well, just not for sleeps: - NTP adjustments: Can make hard correction of the wall clock, or make the clock tick just a bit faster or slower until the device wall clock synced with the network time. - User adjustments: Users can adjust the device time at any time into any direction. I think we'll have to live with both and I'm not particularly worried about them. My main objective is getting rid of the sleep drift. Fixes #2590 Supersedes #22488, #22585, #23067, #23068 --------- Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
…24903) After Spans #23054, spans that run while the time origin is corrected (e.g. after the device slept) get the drift added to their duration. However, If the wall clock jumps backwards, the duration can even be negative. Also, adding sleep time to spans is arguably unexpected and unprecedented in comparison to OpenTelemetry. This PR changes s `span.end()` without a explicit timestamp to compute the end as start time + `performance.now()` time since the start, [like OpenTelemetry does](https://github.com/open-telemetry/opentelemetry-js/blob/672b1d216e8b2299d16d7e2dfd184da4bf448cb4/packages/sdk-trace/src/Span.ts#L319-L356). Start times still use `timestampInSeconds()`, so real-time started spans and spans from performance entries stay on the same timeline. Tradeoff: when a correction happens while a span runs, its end is now based on the old time origin. So children or errors recorded after the correction can appear after the span ended. Spans with an explicit start time keep using `timestampInSeconds()` for the end. --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Effect spans used Effect's own clock (a fixed origin plus a monotonic clock) for their start, end and event times. #23054 makes Sentry correct its clock for drift (e.g. after the device slept), so Effect spans could end up shifted by the drift relative to the Sentry spans around them. With this PR, an Effect span now starts on Sentry's clock, and its end and event times are converted by their offset from the span's start. This is the same per-span offset that OpenTelemetry's SDK uses. We also do this for our spans now, see #24903 for details. The PR keeps Effect's durations and any end time passed explicitly via `span.end(time, exit)`. With `withTracerTiming(false)`, Effect passes `0`, and we now use Sentry's clock instead of setting 1970 timestamps. Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
…25112) Ports the last three `cloudflare-integration-tests` suites that still pinned `traceLifecycle: 'static'`. `tracing/propagation/worker-do-rpc-overlapping` (#24447) and the two `vite-autoinstrument/*-reexport-instrumented` suites (#23282) landed while the earlier port PRs were open, so those PRs missed them. The re-export suites check that `_INTERNAL_wrapUnlessInstrumented` prevents a double wrap, so I made sure that the ported tests still catch one. With the guard disabled, the Workflow suite receives two `step-one` segment spans, and the WorkerEntrypoint request fails with `TypeError: Cannot redefine property: __SENTRY_CONTEXT__`. ## Still pinned - `suites/basic` stays as the static trace lifecycle guard, as named in #24196. - `suites/request-handler/subpath` stays pinned because of an SDK bug, not a test problem. `wrapRequestHandler` from `@sentry/cloudflare/request` still sends a `transaction` envelope. The `/request` entry never sets an async context strategy, so `getClient()` in `SentrySpan._onSpanEnded` returns `undefined` when the span ends, and the span falls through to `_convertSpanToTransaction`. The scope captured on the span does hold the streaming client. This needs a fix in the SDK. closes #24132 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
## Description This brings back the `http.server` / `http.client` op and the `auto.http.effect` origin on Effect HTTP spans with `effect@4.0.2` and later. The tracer now also maps a span whose name is an HTTP method and whose kind is `server` or `client`. ## Why Effect-TS/effect#8873, released in `effect@4.0.2`, names HTTP spans after the request method only (`GET` instead of `http.server GET`). The tracer derived the op and origin from that name prefix, so the spans lost both, and the `effect-4-node` E2E tests failed on `develop`. ## Span name decisions The tracer keeps the name that Effect sets (`GET`). With the `http.server` op, Sentry shows the segment as `GET /test-transaction`. We could rename it back to `http.server GET`, but Effect chose the OpenTelemetry naming on purpose. ## Known issues - A user span named only after an HTTP method with a `server` or `client` kind also gets the HTTP op. ## Sentry traces Before (`develop`, `effect@4.0.2`, op `http`, origin `manual`): https://sentry-sdks.sentry.io/explore/traces/trace/55137135a9a648f79a53d3a08f4d0546/ After (this PR, `effect@4.0.2`, op `http.server`, origin `auto.http.effect`): https://sentry-sdks.sentry.io/explore/traces/trace/11a9e7bfb1834bfbbdb9c4ddedd3dd76/ Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Internal exception events skip event processors and `beforeSend` to prevent recursion, so they must also omit attachments that those callbacks would normally filter. Exclude attachments when building internal event envelopes, including attachments added by send hooks, while preserving ordinary event attachments and scope state. Fixes [JS-2136](https://linear.app/getsentry/issue/JS-2136). --------- Co-authored-by: GPT-6 <codex@openai.com>
…25127) The soft navigation web vitals tests hid the page right after the click. Chrome only delivers the `soft-navigation` entry once the new route has painted, so it can arrive after the page is hidden. web-vitals then reports CLS for the pageload, and never finalizes the soft navigation's metrics, so the test times out. This was flaky on `develop`, e.g. in [this run](https://github.com/getsentry/sentry-javascript/actions/runs/37587739193), where `vue-3 (latest)` and `vue-3 (vue-router 5)` both timed out. The tests now wait for the `soft-navigation` entry before calling `hidePage`, using a new `waitForSoftNavigation` helper in `test-utils`. Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The Replay integration adding web vital breadcrumbs used the metric value as the timestamp for CLS and INP web vitals. This is incorrect because that value is a score for CLS and a duration for INP, so both events always landed just after page load. This was a pre-existing bug, but it showed up during work on #23054. With this PR, CLS goes at the last layout shift and INP at the interaction, like we already do with spans in tracing. Both also get the time origin from when that happened, so they stay correct after a clock drift correction. A CLS of 0 has no layout shift, so it stays at the start of its navigation --------- Co-authored-by: Claude <noreply@anthropic.com>
Follow-up to #23054, from [this review comment](#23054 (comment)). Besides `visibilitychange`, we now also check for clock drift on `freeze`/`resume` (TIL) and `pagehide`/`pageshow`. This way the time origin is corrected right at the emissions, not at the next regular timestamp call. `freeze` and `resume` only fire in Chromium. Other browsers never fire them, so the listeners do nothing there. --------- Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
SvelteKit 3 builds all environments in a single Vite build and runs the adapter in a post `buildApp` hook. Our upload waited for a separate SSR build in `closeBundle`, which Kit 3 never does, so nothing was uploaded. We now also upload from a post `buildApp` hook, but only once an environment has been built. Kit 2 builds only after all `buildApp` hooks have run, so its `closeBundle` path still does the upload. Source maps were also never deleted after upload, on Kit 2 or Kit 3. The deletion check read `build.sourcemap` after our own plugin had already set it. The new `sveltekit-3-sourcemaps` e2e app builds against a mock Sentry server. It asserts that the upload happens, that every debug ID has a map, and that no maps are left in `build/`. Fixes #25096 --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Re-resolves three `@graphql-tools` lockfile entries to replace the vulnerable `@graphql-tools/utils` copy: | Package | Before | After | | --- | --- | --- | | `@graphql-tools/schema` | 10.0.31 | 10.1.3 | | `@graphql-tools/merge` | 9.1.7 | 9.2.6 | | `@graphql-tools/utils` | 11.0.0 | 12.0.3 | Fixes GHSA-7mx3-vvmw-hjmv (high), prototype pollution in `mergeDeep`: https://github.com/getsentry/sentry-javascript/security/dependabot/2696 The first patched release is 12.0.1, so the fix has to cross a major. It still needs no `package.json` change: `@apollo/server` already declares `@graphql-tools/schema@^10.0.0`, and schema 10.1.3 pulls `utils` into 12.x. Lockfile-only diff, dev-only dependency path. Verified with the affected suites, 52 passing: yarn vitest run suites/tracing/apollo-graphql suites/tracing/graphql-tracing-channel Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
(disclaimer, most of the additions are from `withSentry.test.ts` and other tests) Adds `withSentry` from `@sentry/nextjs/cloudflare` for the Worker entry of a Next.js app on Cloudflare Workers, for example `.open-next/worker.js` of OpenNext or the fetch handler of vinext. It is `withSentry` of `@sentry/cloudflare` with the Next.js handling of the server `init` added, so a Next.js app on Workers gets the spans it gets on Node.js from one wrapper, without new options. This is the only new public API. Decisions: - It installs the OpenTelemetry async context strategy at module load. The AsyncLocalStorage strategy of `@sentry/cloudflare` loses the OpenTelemetry context of the Next.js spans, so their parents and context values break. - The request spans of Next.js (`BaseServer.handleRequest`) are ignored, so the request span of `withSentry` is the only `http.server` span. The other Next.js spans become its children; it gets the route from their `next.route` and its status from the response. When the middleware answers the request or throws, the span is named `middleware GET`, like the middleware segment on Node.js. - From `compatibility_date` 2026-02-19, `process.cwd()` is `/bundle` during a request. Next.js then misses its router server context and extracts the incoming trace again. The propagator keeps the request span as parent in that case, else each continued request has two segments. - `sentry.server.config.ts` and `sentry.edge.config.ts` still run in the Worker but create no client there. Their options do not apply, and a debug log says so. On Workers they are optional: they only set the `turbopack` tag and hand over the build release of `withSentryConfig`, which only code that Next.js compiles can read. Without them, the release comes from the `withSentry` options, `SENTRY_RELEASE` or `CF_VERSION_METADATA`. Apps keep them for `next dev`, which runs on Node.js and does not use the Worker entry. `instrumentation.ts` stays required for `onRequestError`. - The Next.js handling is added by a `Nextjs` integration. `withSentry` of `@sentry/cloudflare` creates the client itself (once per isolate), and the options callback only returns options. The `setup` of an integration is the only place that gets this client before the request span starts, without a new option in `@sentry/cloudflare`. It registers the span hooks of the server `init`, the propagator, the tunnel route sampling and the event processor that drops the control flow errors of React and Next.js, so a Worker without `instrumentation.ts` drops them too. The server `init` checks for this integration, so it does not add the processor to the global scope again. - `@sentry/cloudflare` becomes a dependency of `@sentry/nextjs`. Its dependencies are already in the dependency tree of `@sentry/nextjs`. It also aligns with other SDKs, such as `@sentry/sveltekit` Known difference: on Workers, a release from the `withSentry` options, `SENTRY_RELEASE` or `CF_VERSION_METADATA` wins over the build release. On Node.js, the build release wins over the environment. The `nextjs-16-cf-workers` e2e app now uses it, which un-skips its server tests and adds tests for D1 spans, the OpenTelemetry context and trace continuation. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
part of #24830 part of JS-3835 This folds `nextjs-16-bun` and `nextjs-16-cf-workers` into `nextjs-16` and adds a Deno variant, so one suite runs on Node.js, Bun, Deno and Cloudflare Workers (OpenNext). Bun and Cloudflare stay required. Deno and Cloudflare with the latest Next.js are optional. New tests on every runtime check logs, outgoing `baggage` and trace continuation. Most removed lines are the two deleted apps. ## Why The two copies of the app drifted apart, and Deno had no coverage. Now all runtimes run the same tests, and each runtime difference is a visible `getRuntime()` branch or skip. ## Known issues - Bun and Deno need the request isolation and `fetch` integrations of `@sentry/bun` and `@sentry/deno` in `sentry.server.config.ts`. - Deno needs `--allow-sys` (the app runs `deno run -A`). - No `pg` spans on Bun and Workers (no runtime module hook). Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…udflare` (#25000) part of #19514 part of JS-1803 When a Vite build uses vinext and `@sentry/nextjs/cloudflare` resolves from the Worker entry, the Vite plugin of `@sentry/cloudflare` now wraps the entry with `withSentry` from `@sentry/nextjs/cloudflare`. Other builds, and versions of `@sentry/nextjs` without that entry, keep `@sentry/cloudflare`. ```diff -import * as __SENTRY__ from '@sentry/cloudflare'; +import * as __SENTRY__ from '@sentry/nextjs/cloudflare'; const __SENTRY_DEFAULT_EXPORT__ = { fetch() { ... } }; export default __SENTRY__.withSentry(() => undefined, __SENTRY_DEFAULT_EXPORT__); ``` ## Why With `withSentry` of `@sentry/cloudflare`, a vinext app on Workers sends Cloudflare data but no Next.js spans. Now it gets the Next.js spans without a config change. ## Traces The same app and requests: vinext on Workers before and after this PR, and `next start` on Node.js. | Request | vinext before | vinext after | Next.js on Node.js | | --- | --- | --- | --- | | `GET /parameterized/42` | [`GET`, 1 span](https://sentry-sdks.sentry.io/explore/traces/trace/0f98d8ca6ef645e3ae5bb60c039eeb6d/) | [`GET /parameterized/[id]`, 7 spans](https://sentry-sdks.sentry.io/explore/traces/trace/a26de83affd24b0c8fe7990e567ae8b6/) | [`GET /parameterized/[id]`, 7 spans](https://sentry-sdks.sentry.io/explore/traces/trace/c24bdbb12b134e80a5417fe9d2a59c56/) | | `GET /api/hello` | [`GET`, 1 span](https://sentry-sdks.sentry.io/explore/traces/trace/df5b9f7976c5487daa7004cc9361eeeb/) | [`GET /api/hello`, 4 spans](https://sentry-sdks.sentry.io/explore/traces/trace/75b4a831b48f4bb1adb13648f5c6419a/) | [`GET /api/hello`, 4 spans](https://sentry-sdks.sentry.io/explore/traces/trace/ea8990c798144e2db75ee88e8bd6e634/) | | `GET /api/throw` (error) | [`GET`, 1 span](https://sentry-sdks.sentry.io/explore/traces/trace/b6389e0368e44b269e5e07ba9823c29a/) | [`GET /api/throw`, 3 spans](https://sentry-sdks.sentry.io/explore/traces/trace/07caa661217e4f14bb38b182167d08c7/) | [`GET /api/throw`, 3 spans](https://sentry-sdks.sentry.io/explore/traces/trace/c9a3a73e3c7a44d4b7ff6519c8760a7b/) | Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…ts/test-applications/nextjs-sourcemaps (#25170) Bumps [next](https://github.com/vercel/next.js) from 16.2.11 to 16.3.8. <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/vercel/next.js/releases">next's releases</a>.</em></p> <blockquote> <h2>v16.3.8</h2> <p>This release contains security fixes for the following advisories:</p> <p>High:</p> <ul> <li><a href="https://github.com/vercel/next.js/security/advisories/GHSA-cjq9-62q9-8jv4">Server-Side Request Forgery in Image Optimization</a></li> </ul> <p>Medium:</p> <ul> <li><a href="https://github.com/vercel/next.js/security/advisories/GHSA-f87g-xv8r-7p7x">Information disclosure in Next.js App Router metadata image routes via dynamicParams bypass</a></li> <li><a href="https://github.com/vercel/next.js/security/advisories/GHSA-4jqv-mc3x-m676">Cache poisoning of SSG and ISR pages in self-hosted Next.js applications</a></li> <li><a href="https://github.com/vercel/next.js/security/advisories/GHSA-mcj8-r9mp-w47p">Cache poisoning in Next.js SSG/ISR rendering leads to cross-user content substitution and persistent denial of service</a></li> <li><a href="https://github.com/vercel/next.js/security/advisories/GHSA-3w37-wq28-93x7">Pending <code>use cache</code> fill can leak Draft Mode content into regular responses and persisted pages</a></li> <li><a href="https://github.com/vercel/next.js/security/advisories/GHSA-h694-7cp9-m8p3">Cache leak across root param values in nested 'use cache' functions</a></li> </ul> <p>Low:</p> <ul> <li><a href="https://github.com/vercel/next.js/security/advisories/GHSA-39w2-rjm5-chcv">Information disclosure in the Next.js development server's Model Context Protocol endpoint</a></li> </ul> <h2>v16.3.7</h2> <blockquote> <p>[!NOTE] This release is backporting bug fixes. It does <strong>not</strong> include all pending features/changes on canary.</p> </blockquote> <h3>Core Changes</h3> <ul> <li>turbo-tasks-backend: fix strongly consistent read hanging on a canceled task (<a href="https://redirect.github.com/vercel/next.js/issues/98931">#98931</a>)</li> </ul> <h3>Credits</h3> <p>Huge thanks to <a href="https://github.com/lukesandberg"><code>@lukesandberg</code></a> for helping!</p> <h2>v16.3.6</h2> <p>This release contains a security fix for <a href="https://github.com/vercel/next.js/security/advisories/GHSA-vcvr-r3jv-pc5j">GHSA-vcvr-r3jv-pc5j: Remote Code Execution in next/og ImageResponse</a></p> <h2>v16.3.5</h2> <p>The following bug fixes have been backported. It does not include all pending features/changes on canary.</p> <ul> <li>next/image: Skip 0-byte entries when initializing disk LRU cache (<a href="https://redirect.github.com/vercel/next.js/issues/98185">#98185</a>)</li> <li>next/image: Reject empty images when reading/writing to the disk cache (<a href="https://redirect.github.com/vercel/next.js/issues/98186">#98186</a>)</li> <li>Emit whole-app server NFTs when <code>output: 'standalone'</code> is used with an adapter (<a href="https://redirect.github.com/vercel/next.js/issues/98167">#98167</a>)</li> <li>Add CSP nonce to script tags of loading and template files (<a href="https://redirect.github.com/vercel/next.js/issues/98403">#98403</a>)</li> <li>Fix <code>use cache</code> prerender signal retention (<a href="https://redirect.github.com/vercel/next.js/issues/98448">#98448</a>)</li> </ul> <h2>v16.3.4</h2> <p>Follow-up release to <a href="https://github.com/vercel/next.js/releases/tag/v16.3.3">v16.3.3</a> re-enabling AVIF Image Optimization (<a href="https://redirect.github.com/vercel/next.js/pull/97949">#97949</a>).</p> <p>The following bug fixes have been backported. It does <strong>not</strong> include all pending features/changes on canary.</p> <ul> <li>testmode: Fix infinite recursion in testmode passthrough fetch (<a href="https://redirect.github.com/vercel/next.js/issues/97691">#97691</a>)</li> <li>Fix build error when aliasing typescript to <code>@typescript/typescript6</code> (<a href="https://redirect.github.com/vercel/next.js/issues/97997">#97997</a>)</li> <li>Fix unset crossOrigin in Turbopack manifests (<a href="https://redirect.github.com/vercel/next.js/issues/97930">#97930</a>)</li> </ul> <h3>Credits</h3> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Commits</summary> <ul> <li><a href="https://github.com/vercel/next.js/commit/b0fad0d45eb4c4430fda5eeeb442e8a5af08a5f6"><code>b0fad0d</code></a> v16.3.8</li> <li><a href="https://github.com/vercel/next.js/commit/719e4c67d6e92df60246f95e1d96e2dd60789a52"><code>719e4c6</code></a> [lts-active] Scope response cache keys to their source route (<a href="https://redirect.github.com/vercel/next.js/issues/218">#218</a>)</li> <li><a href="https://github.com/vercel/next.js/commit/e92db4536a7f34ae2dbda583cfa1b4e0d06d1865"><code>e92db45</code></a> [lts-active] Fix metadata propagation for deduplicated nested caches (<a href="https://redirect.github.com/vercel/next.js/issues/223">#223</a>)</li> <li><a href="https://github.com/vercel/next.js/commit/40c2ba904289a65ed2fd4633c5dfb1bdc29b52de"><code>40c2ba9</code></a> [lts-active] Match Next data paths case-sensitively (<a href="https://redirect.github.com/vercel/next.js/issues/196">#196</a>)</li> <li><a href="https://github.com/vercel/next.js/commit/2d9f50a409312696145b82b3157aadb6b1fef476"><code>2d9f50a</code></a> [lts-active] Fix MCP middleware DNS rebinding (<a href="https://redirect.github.com/vercel/next.js/issues/213">#213</a>)</li> <li><a href="https://github.com/vercel/next.js/commit/bd9214f9a32854a011bf5fe58e481dffe1bbf598"><code>bd9214f</code></a> [lts-active] Fix draft mode leaks through cross-request <code>'use cache'</code> dedupli...</li> <li><a href="https://github.com/vercel/next.js/commit/8db4a627c91e718514406ff5644ea4985dcaaae0"><code>8db4a62</code></a> [lts-active][webpack] Ensure <code>dynamicParams</code> is respected in `opengraph-image...</li> <li><a href="https://github.com/vercel/next.js/commit/e002ad68bd676bb0ed0c87bb22e3590304763e0b"><code>e002ad6</code></a> [lts-active] fix(next/image): Pin DNS resolution when fetching external image...</li> <li><a href="https://github.com/vercel/next.js/commit/4c20699e29178d444994cf5a31b8a617ca3a2c80"><code>4c20699</code></a> v16.3.7</li> <li><a href="https://github.com/vercel/next.js/commit/2521aec5815e7de2121db253d12dae9f13e25361"><code>2521aec</code></a> [backport] turbo-tasks-backend: fix strongly consistent read hanging on a can...</li> <li>Additional commits viewable in <a href="https://github.com/vercel/next.js/compare/v16.2.11...v16.3.8">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>
Port AMQP tests to span streaming. Part of #24137 --------- Co-authored-by: GPT-6 <codex@openai.com>
Port Tedious tests to span streaming. Part of #24137 --------- Co-authored-by: GPT-6 <codex@openai.com>
Port MySQL and MySQL2 diagnostics-channel tests to default span streaming. Keep the original MySQL2 suite static for transaction coverage. Part of #24137 --------- Co-authored-by: GPT-6 <codex@openai.com>
Adds `piDurableIntegration` for [`@earendil-works/pi-durable`](https://github.com/earendil-works/pi/tree/main/packages/durable), Earendil's new durable agent harness. It is on by default in Node, Bun and Deno, and in a Worker built with `@sentry/cloudflare/vite`, which covers pi-durable in a Durable Object through the Agents SDK `PiHarness`. Each run becomes its own `invoke_agent` trace with `chat` and `execute_tool` children, and the first run of a subagent conversation nests under the tool call that created it. pi-durable has no telemetry hooks (`pi-telemetry` exists, but no pi package emits spans through it yet), so the integration hooks `Harness.open()` and wraps the `models` and `registry` it receives. The wrapped options keep the caller's options as prototype, because pi-durable reads `settings`, `env` and `conversationCreated` at every use. Decisions worth a look: - **Runs are tracked per conversation.** pi-durable hands run control to a new `pi.generation` task after every tool round, so no single task spans a run. The run span ends when the commit that removes `pi.live.run` goes through, or when the Harness closes with the run in flight. - **Each run starts a new trace in clean scopes.** The scheduler runs task phases in whatever async context last woke it, often an unrelated request. Forking that context attached runs to the wrong request and the wrong conversation. Only the client of that context is kept, because `@sentry/cloudflare` binds the client to the scope of each request, not to the default scope. - **`gen_ai.conversation.id` is `<harness id>:<conversation id>`.** pi-durable numbers conversations per storage from 1, so the bare id would merge every root conversation into one. The cost is a new id after a restart (on Cloudflare, after every restart of the Durable Object), until pi-durable has a stable storage id. - **Tool spans record the result the model receives**, read from the committed result entry. That covers output streamed through `api.output()` (all of `bash`) and results an `afterTool` hook redacted. - **Errors:** failures pi-durable only passes to `onReport` (throwing hooks or sections) and task phases that throw are captured. Throws of the built-in coding tools are not, because `bash` throws for every non-zero exit, a normal result for a coding agent. The built-in tools are recognized by their factories (`createBashTool()` and friends), so an app that registers them in an extension of its own gets the same treatment. The span keeps its error status. - **The provider SDK integrations are skipped process-wide** from the first run on, as the Flue and LangChain integrations do: pi-ai sends its requests through the `openai`, `@anthropic-ai/sdk` and `@google/genai` clients, or through the Workers AI binding with `createAI()` of `agents/models/pi-ai`, and those integrations cannot tell pi-ai's calls from the app's own. Bedrock requests go through the AWS SDK, which `awsIntegration` still reports twice; that skip is a follow-up. Messages, token usage and finish reasons go through the pi-ai mapper from the Flue fix, and the system prompt and tools are replayed from pi-durable's positional system messages. Not covered yet: spans for tool calls pi-durable answers without running `execute()`, spans for custom tasks, agent names (pi-durable has none), a link between a run and the request that submitted it, a marker for compaction requests, and an error event for a failed model request (the `chat` span carries the status). 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Andrei <168741329+andreiborza@users.noreply.github.com>
Adds an E2E app for the pi-durable instrumentation. It covers what the node integration test cannot: the packed SDK loaded with `--import`, real model requests through OpenRouter, SQLite storage, a subagent, and a run that resumes after the server crashes during a tool call. A small supervisor restarts the server for that case, as a process manager would. pi-ai sends `anthropic/claude-haiku-4.5` through `@anthropic-ai/sdk`, so the first test also checks that each model request is reported once and that the provider's HTTP call nests inside its `chat` span. The app is optional with a `latest` variant, because `E2E_OPENROUTER_API_KEY` is only available in the optional E2E job. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
The Agents SDK `PiHarness` ([changelog](https://developers.cloudflare.com/changelog/post/2026-10-02-pi-harness/)) keeps the state of pi-durable in the SQLite database of the Durable Object, in tables with the `pi_` prefix of its session store. Each statement became a `db.query` span: one run with one tool call had 189 of them next to its 7 agent spans, and the request that submitted the prompt had 120 more. These statements are framework bookkeeping, like the ones on the `cf_` tables of `agents`, so they are now skipped the same way, and `durableObjectSqlSpanAllowlist: [/^pi_/]` brings them back. The cost is the same as for `cf_`: a user table whose name starts with `pi_` also loses its spans until it is on the allowlist. Names such as `api_keys` or `pipelines` are not affected. Before: [196 spans](https://sentry-sdks.sentry.io/explore/traces/trace/7da432828f034a709be522a7de5bd4e2/), after: [7 spans](https://sentry-sdks.sentry.io/explore/traces/trace/0a8c909bd53a4d61b78f98af21fc1ebb/) for the same prompt. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Cloudflare now hosts pi-durable in Durable Objects through the Agents SDK `PiHarness` ([changelog](https://developers.cloudflare.com/changelog/post/2026-10-02-pi-harness/)). This app runs pi-durable that way, with `@sentry/cloudflare/vite` as the only Sentry setup. It checks that a prompt becomes an `invoke_agent` trace with `chat`, `execute_tool` and provider `http.client` spans, that a throwing tool is reported on its span, and that a run resumes in a new trace after the Durable Object resets during a tool call. The reset uses `ctx.abort()`, which drops the object like an eviction; the next request starts it again, and `PiHarness` resumes pi from its SQLite state. Like `node-pi-durable` and `cloudflare-think`, it calls a real model through OpenRouter, so it is optional. The changelog example uses Workers AI (`createAI({ binding: env.AI })`), but the AI binding needs a Cloudflare account even in local dev, so that path has a unit test in #24993 instead. This app found a bug that #24993 now fixes: `@sentry/cloudflare` initializes the SDK inside each request, so the client is on the scope of that request only. The task phases ran on a copy of the default scope, had no client, and dropped every pi-durable span and error. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
…ate spans (#25044) ## What Mastra classifier evaluations (Jev calls through Mastra's `Classifier`, its processors and scorers) now show up as `gen_ai.evaluate` spans with model, provider and token usage. When gen_ai recording is on, they also record the evaluated state, questions and answers. ## Why These calls skip the AI SDK hook, and our Mastra exporter dropped their spans, so they were invisible. Closes: #25031 --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
## What Adds a node-mastra e2e test that runs a real Jev evaluation through a Mastra `Classifier` (via OpenRouter) and checks the `gen_ai.evaluate` span. ## Why Covers the classifier instrumentation from #25044 against the real provider, not only a mock model.
Browser page loads in Remix 3 started a new trace. The server middleware now adds `sentry-trace` and `baggage` entries to the `Server-Timing` header of HTML responses, ahead of the route entry, the same channel the Remix 2 SDK and Nitro use. The browser SDK already reads both off the navigation timing entry for page loads, so no client change is needed. A response a shared cache may store (`public`, `s-maxage`, or a positive `max-age` without `private`/`no-store`) carries the route entry only: a cached document would otherwise hand one request's trace to every later page load, the ISR problem the Next.js SDK works around on the client. The e2e test asserts that the page load span shares the server span's trace id and has it as parent. Fixes #25137 --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
size-limit report 📦
|
| * them from the call. Mastra ends its span before `evaluate()` returns the answers, so the exporter | ||
| * leaves the Sentry span open and the integration ends it once the call settles. | ||
| */ | ||
| export interface ClassifierEvaluationCall { |
There was a problem hiding this comment.
Bug: The module-level singleton startingCall creates a race condition. Concurrent Classifier.evaluate() calls can overwrite this variable, leading to mismatched or lost trace data.
Severity: HIGH
Suggested Fix
Replace the global startingCall singleton with a context-aware mechanism like AsyncLocalStorage to maintain state per asynchronous execution context. Alternatively, correlate calls using their unique message object instead of relying on a shared global variable to avoid race conditions.
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/ai/mastra/classifier-evaluation.ts#L10
Potential issue: A race condition exists due to the module-level singleton
`startingCall` in `classifier-evaluation.ts`. In a concurrent environment, if two
`Classifier.evaluate()` calls start close together, the second call's `channel.start`
handler can overwrite the `startingCall` variable before the first call's `span_started`
handler runs. This causes `takeStartingClassifierEvaluation()` to return the wrong call
object for the first evaluation and potentially `undefined` for the second. The result
is corrupted trace data, where spans are attributed to the wrong evaluation or lost
completely. This is likely to occur in a production server handling multiple concurrent
requests.
Also affects:
packages/server-utils/src/integrations/mastra-classifier.ts:29~31packages/server-utils/src/integrations/mastra-classifier.ts:58~60
Did we get this right? 👍 / 👎 to inform future reviews.
No description provided.