Skip to content

meta(changelog): Update changelog for 10.63.0#21874

Merged
JPeer264 merged 35 commits into
masterfrom
prepare-release/10.63.0
Jul 1, 2026
Merged

meta(changelog): Update changelog for 10.63.0#21874
JPeer264 merged 35 commits into
masterfrom
prepare-release/10.63.0

Conversation

@JPeer264

@JPeer264 JPeer264 commented Jul 1, 2026

Copy link
Copy Markdown
Member

No description provided.

mydea and others added 30 commits June 26, 2026 11:38
This adds a new method, `extendIntegration`, that can be used to safely
extend an integration.

Today, we have the problem that if we extend an integration (e.g. node
extending something from server-utils), we have to manually call the
parent integration functions. This is a bit brittle because a) it
requires you to know exactly what methods the parent integration has,
which we usually want to abstract away from users on purpose. also, if a
parent integration changes, this could be forgotten/lost.

Usage:

```js
const _denoMysqlIntegration = (() => {
  const inner = mysqlChannelIntegration();

  return extendIntegration(inner, {
    name: INTEGRATION_NAME,
    setupOnce() {
      setAsyncLocalStorageAsyncContextStrategy();
    },
  });
}) satisfies IntegrationFn;
```

vs. before:

```js
onst _denoMysqlIntegration = (() => {
  const inner = mysqlChannelIntegration();
  return {
    name: INTEGRATION_NAME,
    setupOnce() {
      setAsyncLocalStorageAsyncContextStrategy();
      inner.setupOnce?.();
    },
  };
}) satisfies IntegrationFn;
```

In addition, I also improved `defineIntegration` to maintain a static
name, and made all integration names static for easier access.

Note: We have a bunch of places where we started to type integrations
manually, e.g.

```ts
export const denoMysqlIntegration = defineIntegration(_denoMysqlIntegration) as () => Integration & {
  name: 'DenoMysql';
  setupOnce: () => void;
};
```

We should revert this in v11. We purposefully did not do this because we
want to keep the underlying implementation flexible. I think this was
done sometimes to make it easier to extend/call things, but usually this
should not be necessary and the extend helper should help with making
things type safe a bit easier.
[Gitflow] Merge master into develop
…gin (#21782)

Adds a Nuxt 4 E2E test app that shows how orchestrion (build-time
`diagnostics_channel` injection) can be wired into a meta framework, so
DB instrumentation works on bundled server code without `--import`.

- Rollup plugin instead of Vite. Nuxt's server is built by Nitro
(Rollup), so the orchestrion code transform is wired in as a Nitro
Rollup plugin, mirroring the existing Vite plugin.

- Local module to inject `init` to "server entry". Nitro does not expose
an explicit server entry to place the Sentry init in. A small local Nuxt
module (mirroring `@sentry/nuxt`'s `addSentryTopImport`) injects a
top-level `import './sentry.server.config.mjs'` into Nitro's built
entry, so `node .output/server/index.mjs` initializes Sentry first

- Both instrumentation paths coexist. orchestrion handles the bundled
`mysql` (auto.db.orchestrion.mysql), while OTel keeps instrumenting
everything left external (`ioredis`, `http`, …)
closes #21626

Inspired by the Cloudflare and Bun integration tests runner:
`.unordered()`
…equests (#21769)

The server SDK was turning every incoming tunnel route request into an
`http.server` transaction. This drops tunnel traffic for both the static
and streamed (`traceLifecycle: 'stream'`) span lifecycles.

closes #21555
ref(node): Replace `@opentelemetry/api` in lru-memoizer instrumentation with sentry APIs
…21786)

Adds an orchestrion-based lru-memoizer integration replacing the
equivalent otel integration if enabled. This currently supports
`>=2.1.0`, which should be sufficient I think since `<2.1.0` is [barely
used
anymore](https://www.npmjs.com/package/lru-memoizer?activeTab=versions).

Closes #20759

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
## Problem

The Cloudflare SDK README and several Cloudflare test fixtures still
allow or use `nodejs_als`, but the SDK now needs the broader
`nodejs_compat` flag as the minimum compatibility setting for current
and future Node.js API usage.

Fixes #18803.

## Solution

I updated the Cloudflare README to document `nodejs_compat` as the
required flag, adjusted the async context comment to match`.
…21785)

Exposes a public `isTracingSuppressed` helper from `@sentry/core` and
routes it through the async context strategy, mirroring
`suppressTracing`.

Previously `isTracingSuppressed` only existed as a private helper that
checked the scope's SDK processing metadata. That's correct for the core
(stack) strategy, but on OTel-based SDKs (e.g. Node) tracing suppression
lives on the active OpenTelemetry context — so a metadata-only check
could disagree with `suppressTracing`. Routing through the async context
strategy keeps the two consistent across runtimes.

### Changes
- **`@sentry/core`**: export `isTracingSuppressed`, which delegates to
`acs.isTracingSuppressed` and falls back to the scope-metadata check.
Added `isTracingSuppressed` to the `AsyncContextStrategy` type and
replaced the private `_isTracingSuppressed` usages.
- **`@sentry/opentelemetry`**: implement `isTracingSuppressed` (reads
the active OTel context) and register it on the async context strategy.
- **`@sentry/node-core`**: `SentryHttpInstrumentation` and
`SentryNodeFetchInstrumentation` now call core's `isTracingSuppressed()`
instead of importing it from `@opentelemetry/core`.
- Added unit tests in `@sentry/core` and `@sentry/opentelemetry`.

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

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…21778)

This streamlines and de-otelifies the undici instrumentation in node
package.

Note that there is still a OTEL instrumentation (channel based, but
still) in node-core which can be updated in a separate follow up step.

This also updates to use sentry/conventions and drop any config we hard
coded so far, streamlining this. Also, unsubscribe code was removed and
other things we do not need were removed.
We rely on the async local storage instance for the tracing channel
bindings.

Previously, this was picked up from the otel context manager (in
otel-mode). However, this is only setup after the integrations run,
leading to a race condition where this was not available yet.

The "fix" for this we used so far was to setup the channel-based
listeners in the next tick via `Promise.resolve()`. Apart from being a
bit hacky, this also has a concrete problem: If code runs synchrounsly
after Sentry.init(), this could be unhandled by our integration (this
was surfaced when moving vercel ai v6 to use orchestrion, where this
failed in CJS).

So this PR changes this a bit, so that in the happy path where we use
our own context manager, we can use a consistent instance of async local
storage even before the manager is setup. In this case, we can setup the
integrations in a sync way and everything just works.

If users use a custom context manager, this will/may not work though. So
in this case we continue to use the lookup from the context manager
(this can be removed in v11). Since this means we have the same problems
as before, I added a small utility `waitForTracingChannelBinding` to
abstract this away - this will try to see if this is setup and if so,
exectute the provided callback synchronously. Else, it will wait a tick
and try again (mirroring what we had before).

While at this, I also cleaned up internal exports from core a bit - one
of them can be reproduced with more public APIs already, we just never
exported `getAsyncContextStrategy` from core but this is fine to export
IMHO.

I also adjusted the type a bit so that `asyncLocalStorage` in the
binding is unknown but non nullable, as this could accidentally become
undefined which would not be caught by types but is not really intended
- in this case the whole binding should be undefined.
…pans (#21833)

# What

Forward the isolation scope's `normalizedRequest` into the
`tracesSampler` sampling context for root spans. `_startRootSpan` now
includes it in the object passed to the sampler.

# Why

`SamplingContext` already advertises a `normalizedRequest` field, and
server SDKs already record the incoming request on the isolation scope,
but core never wired the two together for root spans, so `tracesSampler`
always received `normalizedRequest: undefined` on the standard root-span
path. This closes that gap so custom samplers can decide based on the
incoming request (drop health-check routes, raise the rate for `/api/*`,
key off the HTTP method) instead of reverse-engineering it from the span
name or attributes, which for an incoming HTTP root span may not yet
carry the route at sampling time.

Extracted standalone from #21666 (the `SentryTracerProvider` stack): it
has no dependency on that work, ships on its own merits, and shrinks
#21666's review surface.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Streamlines the vendored `@opentelemetry/instrumentation-mysql`
(#20738), mirroring the already-streamlined `mysql2` sibling.

## Changes
- **Step 4 (Sentry APIs):** span creation moves from the OTel tracer to
`startInactiveSpan`, with the `auto.db.otel.mysql` origin set directly
(new — matches mysql2; the existing tests don't assert origin).
- **Step 2 (remove unused):**
- Connection-pool **metrics** (`db.client.connections.usage` counter,
pool event listeners, `_patchPoolEnd`/`_patchAdd`/`_setPoolCallbacks`,
`getPoolNameOld`) — Sentry doesn't consume OTel metrics.
- **Semconv-stability dual-emission** — collapsed to the default OLD
attribute set (`db.system`/`db.name`/`db.user`/`db.statement`,
`net.peer.name`/`net.peer.port`), which is what's emitted today.
- The unused **`enhancedDatabaseReporting`** option (the public
`mysqlIntegration()` can't set it) + `getDbValues`/`AttributeNames`;
`MySQLInstrumentationConfig` collapses to `InstrumentationConfig` (so
`types.ts`/`AttributeNames.ts` are deleted).
- **Step 3 (lint):** removed `/* eslint-disable */` from all vendored
files; they pass the type-aware linter via the shared vendored override.

The OTel **context plumbing**
(`trace.setSpan`/`context.with`/`context.bind` + the pool
`getConnection` context propagation) is intentionally **kept** to
minimize behavior change.

## Verification
- Build + type-aware lint clean.
- **No change to emitted spans.** The existing mysql integration tests
(step 1, already present) cover the query/callback/stream paths against
a real MySQL. Since Docker isn't available in my environment I couldn't
run them locally, but a fake-connection smoke test confirms the span
output is unchanged:
`op: 'db'`, description `'SELECT 1 + 1 AS solution'` (from
`db.statement`), `origin: 'auto.db.otel.mysql'`,
`db.system`/`net.peer.name`/`net.peer.port`/`db.user` as asserted by the
tests.

Closes #20738

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This PR adds the external contributor to the CHANGELOG.md file, so that
they are credited for their contribution. See #21659

Co-authored-by: JPeer264 <10677263+JPeer264@users.noreply.github.com>
This PR changes two things:

1. Set `nodejs_als` where `nodejs_compat` is not needed, just to check
if we are compatible in v10
2. Add `--include-runtime=false` for generating wrangler types
…lient` (#21814)

Now that all our server runtime SDKs support span streaming (they didn't
initially), we can move the per-SDK-init-based logic to add
`spanStreamingIntegration` if `traceLifecycle: 'stream'` was set, to the
`ServerRuntimeClient`.

This makes span streaming enabling more consistent for setups that only
use a client. Also for SDKs like electron that init themselves with e.g.
a `NodeClient` and therefore had to manually add the integration. h/t
@timfish for raising this
Instead of requiring us to keep this as a string list, we can infer this
from the integrations that are defined.
Also small cleanup of integration names to make infernal possible (not
really used right now but may be helpful to debug things in the
future...)
This fails on CI as soon as anything touching DC is exported (type wise)
from server-utils, e.g.
https://github.com/getsentry/sentry-javascript/actions/runs/28358230203/job/84050855524

This PR injects a minimal type shim for the diagnostics channel module
into the 3.8 d.ts file so this works there as well. We can remove this
in v11.
This attribute is needed for resource span description inference in
Relay (span streaming)

closes #21749
…fo extraction (#21822)

When a traced operation throws or rejects, we now set `error.type` and
`sentry.status.message` attributes on the span alongside the existing
error status, so the error type lines up with the rest of our span
conventions.

We talked about this yday, generally tracing channels allow us to
observe more errors than before in some cases but these errors are not
necessarily "unhandled", but we can still set the error attributes so
our users can understand more about the op failure even if handled.
…d http.fragment (#21848)

## What

Strip the leading `?`/`#` from the inferred `http.query` and
`http.fragment` span attributes in `descriptionForHttpMethod`.

## Why

The inferred values were taken straight from `URL.search`/`URL.hash`,
which include the leading `?`/`#`. The OTel SDK span exporter (`getData`
in `spanExporter.ts`) slices these off, so the same logical attribute
ended up in two different formats depending on the code path. Stripping
the prefix here makes both paths emit the same canonical format.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…ation (#21852)

Adds `TODO(v11)` markers at the two spots that strip the leading `?`/`#`
from `http.query`/`http.fragment` — the span exporter's `getData` and
`parseSpanDescription`'s `descriptionForHttpMethod`.

Per the [discussion on
#21848](#21848 (comment)),
`http.query` is specced to *keep* the leading `?`, so the stripping
diverges from our own conventions. The v11 direction is to emit the
OTel-standard `url.query`/`url.fragment` (no leading char, already in
`@sentry/conventions`) and drop `http.query`/`http.fragment`.

Comment-only, no behavior change.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…essage` attribute (#21811)

Fixes a semi-deliberate oversight (lol) from my end that caused span
status messages to be discarded when creating a `StreamedSpanJSON` from
a `Span` instance. The deliberate part was to get rid of complicated
statuses overall. The oversight was that there's a good use case to
augment an `error` status span with a message: We sometimes want to
record that an operation tracked by a span errored but explicitly _not_
capture an error for it (since users likely try/catch said operation).
Classic example is `Connection Refused` for databases.

closes #21800
…21844)

Uses the `whenIdleOrHidden` callback to send the initial session
envelope when the browser has some idle time or at the latest, when the
page is hidden. For old Safari versions, we fall back to `setTimeout`
but otherwise we use `requestIdleCallback` (both within
`whenIdleOrHidden`).

This should improve initial SDK initialization performance as well as
reduce implicitly caused overhead (like increased LCP), due to the
eagerly sent network request.

This should be a fairly safe change to make. I don't think we risk
loosing a lot of sessions with it, given RIC should fire relatively
soon. At the same time, I'm curious how much it improves lighthouse
scores (which we can check easiest after merging).

closes #21817
Streamlines the vendored Prisma instrumentation onto Sentry's span APIs
(v6/v7):

- Folds attributes previously set via the `spanStart` hook into span
creation in the instrumentation.
- Uses `startSpanManual`/`startInactiveSpan` from `@sentry/core` instead
of the OTel tracer in the vendored tracing helper.
- Removes unused code: `setTracerProvider`/`tracerProvider` and unused
contract types (`EngineTrace`, `EngineTraceEvent`, `LogLevel`).

v5 cleanup will be done in a followup.

Part of #20744

Closes #21820

---------

Co-authored-by: Nicolas Hrubec <nico.hrubec@sentry.io>
## Background

same as with #21856 I came across this with adding the Prisma
integration to Cloudflare.

<img width="822" height="428" alt="Screenshot 2026-06-30 at 11 23 57"
src="https://github.com/user-attachments/assets/5eff699b-6275-4b99-8627-9062a0ee7e5d"
/>


## What has changed

The `@sentry/opentelemetry` SDK has some side effect imports, which
don't do anything:
https://unpkg.com/@sentry/opentelemetry@10.62.0/build/esm/index.js

those are the imports
```js
import '@sentry/conventions/attributes';
import '@opentelemetry/core';
import '@opentelemetry/sdk-trace-base';
```

`hoistTransitiveImports` has been added to get rid of the side effect
imports. However, I'm confused with this option, as [the
docs](https://rollupjs.org/configuration-options/#output-hoisttransitiveimports)
say that this option is actually ignored when `preserveModules` have
been set (but it still has an effect).

Also here, if someone has a better idea - I'm all ears.
…res (#21860)

Docker-backed integration suites intermittently go red before any test
logic runs. `runDockerCompose` executed `docker compose up --wait`
exactly once and threw on the first non-zero exit, so transient Docker
daemon races became build failures.

This retries `up` up to 3 times, tearing down between attempts. Real
healthcheck failures stay red on every attempt, so only the transient
infra races are absorbed.

### Root cause

The flake surfaces as the daemon creating the compose network and then
losing it as the container starts:

```
 Network mysql2_default  Created
 Container integration-tests-knex-mysql2  Starting
Error response from daemon: failed to set up container networking: network mysql2_default not found
```

This is a containerd/libnetwork race (more likely with 16 docker suites
running concurrently under vitest threads), not a problem with the
instrumentation under test.

Fixes #21752
Fixes #21751

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…abled (#21141)

Problem is that we do not have a consistent way of detecting stale meta
tags so we rather disable them for `cacheComponents`.

This stops the SDK from enabling Next's
`experimental.clientTraceMetadata` (`sentry-trace`/`baggage`) when
`cacheComponents` is enabled. With no meta tags injected, the browser
pageload starts a fresh, self-contained trace instead of stitching onto
a stale one. Apps that don't use Cache Components are unaffected.

closes
https://linear.app/getsentry/issue/JS-2782/cachecomponents-setup-breaks-meta-tag-injection

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
mydea and others added 4 commits July 1, 2026 08:23
…tion` (#21706)

This is the first part of
#20745,
streamlining fastify v5 instrumentation:

* This is already diagnostics channel based!
* Moved it from node to server-utils package, which now exports a
fastifyIntegration (with support for fastify v5 only as of now) which
can also be used by deno and bun and others in follow ups.
* The integration itself was updated to properly use sentry-specific
methods etc.
* Missing is some any/eslint cleanup - there is a lot of this going on
and it is rather cumbersome to fix it so I opted to mostly leave it as
is.
* Also added some node integration tests for fastify v5 for easier
testing/iteration - this was previously only covered by e2e tests.
* Already moved it to use sentry conventions while at it

Some other general notes:

* This deprecates the `instrumentFastify` method and no longer calls it
in preload, as this does not actually need to be preloaded anymore.
* error handler stuff is still exported from server-utils as we need
this for the old-style error handler. this can probably all be moved to
server-utils in later steps when we moved the v3/v4 instrumentation as
well.
* The auto-error handling in fastify v5 does not work on node 18. this
is a pre-existing problem though and not related to this PR, you'll have
to add the error handler there.
…d route (#21869)

The `request data extraction` tests in
`hono-4/tests/route-patterns.test.ts` fetched the bare `GET
/test-routes` and `POST /test-routes` routes. Those same routes are hit
in parallel by the `HTTP methods` and `route registration styles` test
blocks, producing transactions with identical `transaction` names.

Because `waitForTransaction` resolves on the first event matching its
predicate, the request-data tests could match a transaction produced by
an unrelated parallel test. This is most visible in the POST case: its
filter (`POST /test-routes`) also matches the `HTTP methods` POST test's
transaction, which does **not** carry the `X-Custom-Header`, so the
`x-custom-header` assertion could fail non-deterministically.

The file already established a precedent for this — the `/query-test`
route was added specifically "to avoid transaction name collisions".
This applies the same pattern to the remaining request-data tests by
routing them through a dedicated `/request-data` endpoint, so their
`waitForTransaction` filters can no longer collide with the other
blocks.

Assertions are unchanged: the `url` check still matches
(`/test-routes/request-data` contains `/test-routes`), and the
method/header assertions are preserved — coverage is identical, only the
routing is isolated.

_Root cause_: transaction-name collision between parallel test blocks
sharing the `GET`/`POST /test-routes` routes.

Fixes #21810

Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
…error ordering (#21870)

Fixes the flaky `postgresjs auto instrumentation > basic > should
auto-instrument \`postgres\` package [esm]` Node integration test.

_Root cause_

The `basic` test is the only postgresjs test that expects **two
differently-typed envelopes** — a `transaction` followed by an error
`event`:

```ts
.expect({ transaction: EXPECTED_TRANSACTION })
.expect({ event: EXPECTED_ERROR_EVENT })
```

The scenario's final query targets the just-dropped `"User"` table, so
it rejects with a `PostgresError`. That rejection propagates out of
`run()` as an **unhandled promise rejection**, which Sentry captures on
a *later* event-loop tick than the transaction (the transaction is
captured synchronously when the root span ends). Because the two
envelopes are produced on different ticks, their arrival order at the
transport is not deterministic.

By default the test runner matches envelopes in **order**
(`expectedEnvelopes.shift()`), so whenever the error event happened to
reach the transport before the transaction, the runner threw `Expected
envelope item type 'transaction' but got 'event'` and the test failed —
a textbook intermittent flake. The other three describe blocks each
expect only a single transaction envelope, which is why only `basic`
flaked.

_Fix_

Add `.unordered()` to the `basic` runner chain so the two envelopes may
arrive in either order. Both the transaction (with all its spans) and
the error event are still fully asserted with the same content matchers
— only the brittle arrival-order constraint is removed. This mirrors the
existing precedent in `suites/tracing/apollo-graphql/test.ts`, which
uses `.unordered()` for the same class of non-deterministic
multi-envelope ordering.

Fixes #21790

Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…est (#21868)

The `knex` + `mysql2` node integration test
(`suites/tracing/knex/mysql2/test.ts`) flakes intermittently on CI.

### Root cause

The suite's `docker-compose.yml` gated readiness on:

```yaml
test: ['CMD-SHELL', 'mysqladmin ping -h 127.0.0.1 -uroot -pdocker']
```

`mysqladmin ping` reports the server as *alive* even when it receives an
**access-denied** error, and MySQL 8 spins up a temporary bootstrap
server during first-time initialization (before the root password is
applied and the `tests` database is created). As a result, `docker
compose up -d --wait` — which the runner uses to block until healthy —
can return **before the real server is ready**. The scenario then races
the DB init and the query spans never arrive, so the transaction
assertion times out.

The `pg` sibling suite already avoids this class of bug by checking the
actual database with `pg_isready -U test -d tests`.

### Fix

Make the mysql2 healthcheck run an authenticated query against the
`tests` database, mirroring the pg pattern:

```yaml
test: ['CMD-SHELL', 'mysql -h 127.0.0.1 -uroot -pdocker -e "SELECT 1" tests']
```

This only passes once the real server is up, the root password works,
and `tests` exists — so `--wait` no longer returns prematurely.

Fixes #21861

Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com>
@JPeer264 JPeer264 self-assigned this Jul 1, 2026
@JPeer264 JPeer264 requested review from a team as code owners July 1, 2026 08:24
@JPeer264 JPeer264 requested review from Lms24, andreiborza, chargome, logaretm, mydea and s1gr1d and removed request for a team July 1, 2026 08:24
Comment thread CHANGELOG.md Outdated
Comment thread CHANGELOG.md
Comment on lines +29 to +30
- feat(server-utils): Add lru-memoizer diagnostics-channel integration ([#21786](https://github.com/getsentry/sentry-javascript/pull/21786))
- feat(server-utils): Expose channel-based, streamlined `fastifyIntegration` ([#21706](https://github.com/getsentry/sentry-javascript/pull/21706))

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These are likely not internal

@JPeer264 JPeer264 Jul 1, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I actually moved all of them to internal (clanker put them originally in the main changes) - as server-utils itself is internal. I think I'll make a duplicated entry with feat(node)

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I duplicated 2 of them which also had node SDK changes and added experimentalUseDiagnosticsChannelInjection clarification in one of them

@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

size-limit report 📦

Path Size % Change Change
@sentry/browser 27.62 kB added added
@sentry/browser - with treeshaking flags 26.05 kB added added
@sentry/browser (incl. Tracing) 46.07 kB added added
@sentry/browser (incl. Tracing + Span Streaming) 47.82 kB added added
@sentry/browser (incl. Tracing, Profiling) 50.84 kB added added
@sentry/browser (incl. Tracing, Replay) 85.31 kB added added
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags 74.91 kB added added
@sentry/browser (incl. Tracing, Replay with Canvas) 89.99 kB added added
@sentry/browser (incl. Tracing, Replay, Feedback) 102.67 kB added added
@sentry/browser (incl. Feedback) 44.8 kB added added
@sentry/browser (incl. sendFeedback) 32.42 kB added added
@sentry/browser (incl. FeedbackAsync) 37.55 kB added added
@sentry/browser (incl. Metrics) 28.68 kB added added
@sentry/browser (incl. Logs) 28.93 kB added added
@sentry/browser (incl. Metrics & Logs) 29.61 kB added added
@sentry/react 29.41 kB added added
@sentry/react (incl. Tracing) 48.38 kB added added
@sentry/vue 32.85 kB added added
@sentry/vue (incl. Tracing) 47.93 kB added added
@sentry/svelte 27.64 kB added added
CDN Bundle 30.02 kB added added
CDN Bundle (incl. Tracing) 48.02 kB added added
CDN Bundle (incl. Logs, Metrics) 31.58 kB added added
CDN Bundle (incl. Tracing, Logs, Metrics) 49.35 kB added added
CDN Bundle (incl. Replay, Logs, Metrics) 70.79 kB added added
CDN Bundle (incl. Tracing, Replay) 85.51 kB added added
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) 86.79 kB added added
CDN Bundle (incl. Tracing, Replay, Feedback) 91.32 kB added added
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) 92.56 kB added added
CDN Bundle - uncompressed 89.42 kB added added
CDN Bundle (incl. Tracing) - uncompressed 145.35 kB added added
CDN Bundle (incl. Logs, Metrics) - uncompressed 94.12 kB added added
CDN Bundle (incl. Tracing, Logs, Metrics) - uncompressed 149.32 kB added added
CDN Bundle (incl. Replay, Logs, Metrics) - uncompressed 218.66 kB added added
CDN Bundle (incl. Tracing, Replay) - uncompressed 264.36 kB added added
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed 268.32 kB added added
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed 278.06 kB added added
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed 282.01 kB added added
@sentry/nextjs (client) 50.76 kB added added
@sentry/sveltekit (client) 46.46 kB added added
@sentry/core/server 77.75 kB added added
@sentry/core/browser 64.06 kB added added
@sentry/node-core 61.47 kB added added
@sentry/node 122.07 kB added added
@sentry/node/import (ESM hook with diagnostics-channel injection) 69.95 kB added added
@sentry/node/light 50.45 kB added added
@sentry/node - without tracing 73.2 kB added added
@sentry/aws-serverless 84.09 kB added added
@sentry/cloudflare (withSentry) - minified 180.62 kB added added
@sentry/cloudflare (withSentry) 446.93 kB added added

@JPeer264 JPeer264 force-pushed the prepare-release/10.63.0 branch from f9680e5 to 4e16503 Compare July 1, 2026 08:46
@JPeer264 JPeer264 requested a review from chargome July 1, 2026 08:46
Comment on lines +10 to +14
export function defaultShouldHandleError(_error: Error, _request: FastifyRequest, reply: FastifyReply): boolean {
const statusCode = reply.statusCode;
// 3xx and 4xx errors are not sent by default.
return statusCode >= 500 || statusCode <= 299;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: The defaultShouldHandleError function for Fastify incorrectly captures errors with 2xx status codes, leading to unnecessary Sentry reports. The condition should likely only capture 5xx errors.
Severity: LOW

Suggested Fix

The condition in defaultShouldHandleError should be changed to only capture server errors. Align the logic with the Express integration by changing return statusCode >= 500 || statusCode <= 299; to return statusCode >= 500;. This ensures that only genuine server-side errors (5xx) are reported to Sentry, matching the documented intent and behavior of other framework integrations.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.

Location:
packages/server-utils/src/integrations/tracing-channel/fastify/utils.ts#L10-L14

Potential issue: The `defaultShouldHandleError` function for the Fastify integration
uses the condition `statusCode >= 500 || statusCode <= 299`. This logic incorrectly
captures errors that occur with a 2xx status code, which are not typically considered
server errors. While it's unusual for an error to be thrown when the status code is 2xx,
it is technically possible within Fastify's `onError` hook. This behavior is
inconsistent with other Sentry integrations like Express (`status >= 500`) and Hono, and
contradicts the code comment which implies only 5xx errors should be captured. This will
lead to unnecessary error reports in Sentry.

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

@JPeer264 JPeer264 merged commit 5b51d5e into master Jul 1, 2026
556 of 559 checks passed
@JPeer264 JPeer264 deleted the prepare-release/10.63.0 branch July 1, 2026 09:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants