Skip to content

ref(core)!: Replace deprecated http.* and net.* span attributes on HTTPS spans - #23423

Draft
msonnb wants to merge 1 commit into
developfrom
ms/deprecated-http-net-attributes
Draft

ref(core)!: Replace deprecated http.* and net.* span attributes on HTTPS spans#23423
msonnb wants to merge 1 commit into
developfrom
ms/deprecated-http-net-attributes

Conversation

@msonnb

@msonnb msonnb commented Aug 13, 2026

Copy link
Copy Markdown
Member

Straight renames

  • http.method -> http.request.method
  • http.status_code -> http.response.status_code
  • http.scheme -> url.scheme
  • http.user_agent -> user_agent.original
  • http.flavor -> network.protocol.version
  • http.client_ip -> client.address
  • http.response_content_length -> http.response.body.size
  • http.response_transfer_size -> http.response.size
  • net.peer.ip -> network.peer.address
  • net.host.ip -> network.local.address
  • net.transport -> network.transport
  • url.same_origin -> http.request.same_origin

Changes that are not renames

server.address and server.port

http.host, net.host.name and net.peer.name all map to server.address. They do not hold the same value.

On an HTTP server span, server.* describes the server. The socket peer is the client. The remote address and port therefore go to network.peer.*. The local socket goes to network.local.*.

server.address now comes from the Host header. A new splitHostHeader helper takes the port out of that header and puts it on server.port. The span builders in @sentry/core and @sentry/node both call this helper, so both produce the same attributes.

The unparsed Host header stays available on http.request.header.host.

url.query and url.fragment on core server spans

http.target held the pathname and the query. url.path holds only the pathname.

The server span in @sentry/core set neither url.query nor url.fragment. Dropping http.target would therefore have lost the query. That span now sets both. The server span in @sentry/node already set both.

Consumers that matched on http.target

Two ignoreSpans rules match spans that the SDK itself emits. Both now match on url.path:

  • the low-quality transaction filter in @sentry/react-router
  • the tunnel-route filter in @sentry/tanstackstart-react

Without this change, both rules would match no spans and report no error.

The readers in @sentry/nextjs still read http.target, but only after they read url.path. These readers also receive spans from an OpenTelemetry instrumentation that the user set up, and that instrumentation still emits the old attributes. Every other read-side fallback stays for the same reason.

SanitizedRequestData

This type is the shape of http breadcrumb data. It now uses http.request.method as the key for the request method.

no-unfiltered-url-attributes

This lint rule no longer guards http.target. The SDK no longer sets http.target. Its replacement url.path holds a pathname without a query, so there is nothing to filter.

part of #18895

…n HTTP spans

Part of the v11 migration away from attributes `@sentry/conventions` marks
deprecated. Scoped to HTTP spans; the `net.peer.*` attributes on database and
messaging spans are migrated separately.

Straight renames: `http.method` -> `http.request.method`, `http.status_code` ->
`http.response.status_code`, `http.scheme` -> `url.scheme`, `http.user_agent` ->
`user_agent.original`, `http.flavor` -> `network.protocol.version`,
`http.client_ip` -> `client.address`, `http.response_content_length` ->
`http.response.body.size`, `http.response_transfer_size` ->
`http.response.size`, `net.peer.ip` -> `network.peer.address`, `net.host.ip` ->
`network.local.address`, `net.transport` -> `network.transport`, and
`url.same_origin` -> `http.request.same_origin`.

`http.request_content_length*`, `http.response_content_length_uncompressed` and
`http.status_text` are left alone — they are not in `@sentry/conventions` at
all, so they have no replacement to move to.

Three cases needed more than a rename:

- `http.host`, `net.host.name` and `net.peer.name` all map to `server.address`,
  but do not hold the same thing. On a server span `server.*` describes the
  server and the socket peer is the *client*, so the remote address/port go to
  `network.peer.*` and the local socket to `network.local.*`. `server.address`
  comes from the `Host` header with the port split out into `server.port` by a
  new `splitHostHeader` helper, shared by the core and node span builders so
  the two stay identical. The raw header is still on
  `http.request.header.host`.
- `http.target` carried pathname *and* query, while `url.path` is the pathname
  only. The core server span set neither `url.query` nor `url.fragment`, so
  dropping `http.target` would have lost the query — it now sets both, which
  the node server span already did.
- Consumers that matched on `http.target` were repointed at `url.path`: the
  react-router low-quality-transaction filter and the TanStack Start
  tunnel-route filter, both `ignoreSpans` rules against our own spans that
  would otherwise have silently stopped matching. The Next.js readers keep
  `http.target` as a fallback behind a `url.path` primary, since they also see
  spans from a user's own OpenTelemetry instrumentation. All other read-side
  fallbacks are untouched for the same reason.

`SanitizedRequestData`, the shape backing `http` breadcrumb data, now keys the
method as `http.request.method`.

Span attributes in the touched files are now imported from
`@sentry/conventions/attributes` rather than written as string literals. That
is what surfaced `url.same_origin` as deprecated; as a literal it was invisible.

`no-unfiltered-url-attributes` no longer guards `http.target`: nothing sets it,
and its replacement `url.path` is a bare pathname with no query to filter.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@msonnb

msonnb commented Aug 13, 2026

Copy link
Copy Markdown
Member Author

bugbot run

@github-actions

Copy link
Copy Markdown
Contributor

size-limit report 📦

Path Size % Change Change
@sentry/browser 30.3 kB - -
@sentry/browser - with treeshaking flags 28.47 kB - -
@sentry/browser - with treeshaking flags tracing without tracing 26.81 kB - -
@sentry/browser (incl. Tracing) 48.58 kB -0.01% -1 B 🔽
@sentry/browser (incl. Tracing + Span Streaming) 48.6 kB +0.02% +6 B 🔺
@sentry/browser (incl. Tracing, Profiling) 51.47 kB +0.02% +8 B 🔺
@sentry/browser (incl. Tracing, Replay) 87.97 kB -0.02% -13 B 🔽
@sentry/browser (incl. Tracing, Replay) - with treeshaking flags 77.37 kB +0.02% +10 B 🔺
@sentry/browser (incl. Tracing, Replay with Canvas) 92.69 kB -0.02% -14 B 🔽
@sentry/browser (incl. Tracing, Replay, Feedback) 105.39 kB -0.01% -4 B 🔽
@sentry/browser (incl. Feedback) 47.65 kB - -
@sentry/browser (incl. sendFeedback) 35.13 kB - -
@sentry/browser (incl. FeedbackAsync) 40.28 kB - -
@sentry/browser (incl. Metrics) 31.24 kB - -
@sentry/browser (incl. Logs) 31.52 kB - -
@sentry/browser (incl. Metrics & Logs) 32.15 kB - -
@sentry/react 32.09 kB - -
@sentry/react (incl. Tracing) 50.78 kB +0.03% +13 B 🔺
@sentry/vue 35.34 kB - -
@sentry/vue (incl. Tracing) 50.53 kB -0.03% -13 B 🔽
@sentry/svelte 30.33 kB - -
CDN Bundle 31.61 kB - -
CDN Bundle (incl. Tracing) 48.91 kB +0.05% +20 B 🔺
CDN Bundle (incl. Logs, Metrics) 33.8 kB - -
CDN Bundle (incl. Tracing, Logs, Metrics) 50.83 kB +0.02% +8 B 🔺
CDN Bundle (incl. Replay, Logs, Metrics) 74.31 kB - -
CDN Bundle (incl. Tracing, Replay) 86.48 kB +0.01% +6 B 🔺
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) 88.33 kB +0.03% +20 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback) 92.2 kB +0.02% +11 B 🔺
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) 94.14 kB +0.03% +19 B 🔺
CDN Bundle - uncompressed 93.84 kB - -
CDN Bundle (incl. Tracing) - uncompressed 146.7 kB -0.04% -50 B 🔽
CDN Bundle (incl. Logs, Metrics) - uncompressed 100.14 kB - -
CDN Bundle (incl. Tracing, Logs, Metrics) - uncompressed 152.39 kB -0.04% -50 B 🔽
CDN Bundle (incl. Replay, Logs, Metrics) - uncompressed 229.08 kB - -
CDN Bundle (incl. Tracing, Replay) - uncompressed 265.96 kB -0.02% -50 B 🔽
CDN Bundle (incl. Tracing, Replay, Logs, Metrics) - uncompressed 271.63 kB -0.02% -50 B 🔽
CDN Bundle (incl. Tracing, Replay, Feedback) - uncompressed 279.66 kB -0.02% -50 B 🔽
CDN Bundle (incl. Tracing, Replay, Feedback, Logs, Metrics) - uncompressed 285.32 kB -0.02% -50 B 🔽
@sentry/nextjs (client) 53.31 kB +0.04% +16 B 🔺
@sentry/sveltekit (client) 49 kB +0.01% +1 B 🔺
@sentry/core/server 65.4 kB +0.03% +16 B 🔺
@sentry/core/browser 51.73 kB +0.01% +5 B 🔺
@sentry/node 116.91 kB -0.1% -114 B 🔽
@sentry/node/import (ESM hook with diagnostics-channel injection) 0 B added added
@sentry/node - without tracing 81.35 kB -0.11% -84 B 🔽
@sentry/aws-serverless 90.79 kB -0.15% -135 B 🔽
@sentry/cloudflare (withSentry) - minified 214 kB +0.01% +13 B 🔺
@sentry/cloudflare (withSentry) 528.94 kB +0.01% +16 B 🔺

View base workflow run

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 4 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 701694c. Configure here.

return { hostname: match[1], port: port <= 65535 ? port : undefined };
}
return { hostname: host || 'localhost', port: undefined };
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Host header parser mishandles IPv6

Medium Severity

splitHostHeader splits on the last : plus digits, so an IPv6 Host value such as [::1]:8080 keeps the brackets in server.address, and a missing header becomes localhost. Both values are wrong for server.address on every incoming server span.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 701694c. Configure here.

// `Host` header land on `server.address`; the header wins when both are set.
// `url.path`, `url.query` and `http.request.method` come from `attributes` below, which is why
// the old `http.target` (path plus query) has no separate replacement here.
[SERVER_ADDRESS]: request.getHeader('host') ?? request.host,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Client spans embed port in address

Medium Severity

Outgoing HTTP spans copy the Host header or URL.host into server.address, so the port stays in the address and server.port is never set. Server spans already split those with splitHostHeader. Client traces therefore disagree with the server spans and with the server.* spec.

Additional Locations (2)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 701694c. Configure here.

'network.local.port': expect.any(Number),
'network.peer.address': expect.any(String),
'server.port': expect.any(Number),
'http.response.status_code': 200,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

E2E tests remap peer port wrongly

High Severity

These toEqual payloads list server.address twice and map net.peer.port to server.port. The second key wins, so the Host-header address is never asserted, and the extra network.peer.port the SDK still emits makes the strict equality fail. I flagged this because the testing conventions in the review rules require tests to assert the new attributes thoroughly.

Additional Locations (2)
Fix in Cursor Fix in Web

Triggered by project rule: PR Review Guidelines for Cursor Bot

Reviewed by Cursor Bugbot for commit 701694c. Configure here.

return (
transactionEvent.contexts?.trace?.data?.['http.target'] === `/generation-functions?metadataTitle=${testTitle}`
);
return transactionEvent.contexts?.trace?.data?.['url.path'] === `/generation-functions?metadataTitle=${testTitle}`;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Tests match query on url.path

High Severity

waitForTransaction and the Next.js 15 tracesSampler now compare url.path to a string that still includes the query. url.path is pathname-only; http.target used to carry path plus query. Those waiters never match, so the tests time out. I flagged this because the testing conventions in the review rules require tests to cover the new attributes correctly.

Additional Locations (2)
Fix in Cursor Fix in Web

Triggered by project rule: PR Review Guidelines for Cursor Bot

Reviewed by Cursor Bugbot for commit 701694c. Configure here.

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.

1 participant