FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

fix(node): Don't mark fetch spans as errors when the caller aborts by 4ktLuffy · Pull Request #25129 · getsentry/sentry-javascript · GitHub

Repository navigation

fix(node): Don't mark fetch spans as errors when the caller aborts - #25129

Open
4ktLuffy wants to merge 1 commit into
getsentry:developfrom
4ktLuffy:fix/node-fetch-abort-not-error
Open

4ktLuffy wants to merge 1 commit into
getsentry:developfrom
4ktLuffy:fix/node-fetch-abort-not-error

Conversation

4ktLuffy commented Oct 7, 2026

Copy link
Copy Markdown

A fetch() span that already got a 200 response ends up with status: error when the caller cancels the body stream (reader.cancel()) or calls AbortController.abort() after the headers arrived. undici reports that as undici:request:error with an AbortError instead of undici:request:trailers, and onError in the undici instrumentation sets SPAN_STATUS_ERROR for every error.

This ports the check from upstream OpenTelemetry (open-telemetry/opentelemetry-js-contrib#3488, "do not record aborted requests as errors"): if the error is an AbortError, or a DOMException with ABORT_ERR, the span is ended without touching its status. Other errors (connection reset, TypeError: fetch failed, ...) still set the error status as before. I updated the NOTE comment above onError to say so.

This matters for clients that read a stream and then close it as part of normal operation. For example the MCP TypeScript SDK closes its event stream on client close, so every healthy session showed http.client error spans.

Repro

import * as Sentry from "@sentry/node";
import { createServer } from "node:http";

Sentry.init({ dsn: "http://key@127.0.0.1:9/1", tracesSampleRate: 1,
  beforeSendSpan(s) { console.log(s.name ?? s.description, s.status); return s; } });

const srv = createServer((req, res) => {
  if (req.url === "/stream") { res.writeHead(200, { "content-type": "text/event-stream" }); res.write("data: 1\n\n"); return; }
  res.writeHead(200); res.end("ok");
});
await new Promise((r) => srv.listen(0, "127.0.0.1", r));
const base = `http://127.0.0.1:${srv.address().port}`;

await Sentry.startSpan({ name: "root" }, async () => {
  await (await fetch(base + "/plain")).text();                    // ok
  const r = (await fetch(base + "/stream")).body.getReader();
  await r.read(); await r.cancel();                                // error, although the response was 200
});
await Sentry.flush(2000); srv.closeAllConnections(); srv.close();

Before (11.4.0): the fully read request is ok, the cancelled one is error with http.response.status_code 200. Same with AbortController.abort() after the headers arrive.
After (this branch, built with yarn build:dev:filter @sentry/node): both are ok.

Tests

Added unit tests to packages/node/test/integrations/undici.test.ts that publish the undici:request:create, undici:request:headers (200) and undici:request:error diagnostics channel messages:

  • abort errors (AbortError, DOMException named AbortError, DOMException with only the ABORT_ERR code) end the span without an error status
  • control: a TypeError and an ECONNRESET error still set the error status

cd packages/node && yarn vitest run test/integrations/undici.test.ts: without the fix 3 of 10 fail (the abort cases), with the fix 10 of 10 pass. oxfmt --check and oxlint --type-aware are clean on both files.

  • If you've added code that should be tested, please add tests.
  • Ensure your code lints and the test suite passes (yarn lint) & (yarn test). (Ran the changed test file, oxfmt and oxlint on the changed files; not the full suite.)
  • Link an issue if there is one related to your pull request. (There is none; this PR has the repro.)

4ktLuffy requested a review from a team as a code owner October 7, 2026 10:35
4ktLuffy requested review from andreiborza and mydea and removed request for a team October 7, 2026 10:35
github-actions Bot added the external PR from an external contributor label Oct 7, 2026

This branch has not been deployed

No deployments
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

external PR from an external contributor

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant


Back | FazBrowse Home | New Git URL