Skip to content

fix(error-reporting): stop reporting network fetch failures as crashes (CLI-16W)#1152

Merged
BYK merged 2 commits into
mainfrom
byk/fix/network-error-handling
Jun 26, 2026
Merged

fix(error-reporting): stop reporting network fetch failures as crashes (CLI-16W)#1152
BYK merged 2 commits into
mainfrom
byk/fix/network-error-handling

Conversation

@BYK

@BYK BYK commented Jun 26, 2026

Copy link
Copy Markdown
Member

Summary

When the CLI cannot reach the Sentry API — offline, DNS failure, connection
refused/timeout — Node's fetch (undici) rejects with a raw
TypeError: "fetch failed". This escapes uncaught and is reported to Sentry as
a CLI bug. This is CLI-16W
(TypeError: fetch failed, culprit GetAddrInfoReqWrap.onlookupall (node:dns))
17 users, ongoing on 0.38.0.

A "user is offline" report is not actionable for the CLI team — the same class
of noise the codebase already drops for EPIPE/EBADF in beforeSend.

Fix

  • isNetworkError() (new, in errors.ts) — matches the raw
    TypeError: "fetch failed", undici's unambiguous signature for every
    network-level failure (the real errno is in cause).
  • classifySilenced silences network errors (reason: network_error);
    volume is preserved via the cli.error.silenced metric.
  • isUserError treats a raw network TypeError as user-environment (no
    "Upgrading may resolve this" nudge).

Why not ApiError(status 0) (addressing Seer review)

status 0 is shared by genuine connectivity failures and TLS certificate
errors
. TLS errors are actionable user-config issues (e.g. a missing CA cert)
and must stay visible, and isTlsCertError can't reliably re-detect TLS from
the already-wrapped ApiError(0). So isNetworkError deliberately matches
only the raw TypeErrorApiError(status 0), including TLS, stays
captured/actionable. isUserError keeps its explicit status === 0 check so
those still skip the upgrade nudge.

Test plan

  • isNetworkError: raw fetch failed TypeError → true; ApiError(0) (incl.
    TLS), HTTP statuses, unrelated TypeErrors, non-errors → false.
  • classifySilenced: fetch failed TypeError → network_error; TLS
    ApiError(0)not silenced (regression test); unrelated TypeError →
    captured.
  • isUserError: raw fetch failed TypeError → true.
  • reportCliError: network error emits the metric and is not captured.
  • vitest run test/lib/{errors,error-reporting,telemetry,sentry-client}.test.ts
    → 316 passed; biome check clean.

Fixes CLI-16W

When the CLI cannot reach the Sentry API (offline, DNS failure,
connection refused/timeout, proxy), Node's fetch rejects with a raw
"TypeError: fetch failed". handleFetchError only special-cased abort, TLS,
and timeout errors, so generic network failures propagated as an uncaught
TypeError — surfaced to the user as a cryptic crash and reported to Sentry
as a bug (CLI-16W and related DNS/connect-timeout issues).

- Add isNetworkError() in errors.ts (ApiError status 0, or a raw
  "fetch failed" TypeError) as the single source of truth.
- handleFetchError now wraps an exhausted network failure in a clear
  ApiError(status 0) with an actionable message, mirroring throwApiError.
- isUserError treats network errors as user-environment (no upgrade nudge).
- classifySilenced silences network errors (reason network_error): a
  "user is offline" report is not actionable — same rationale as dropping
  EPIPE/EBADF OS noise in beforeSend.
@github-actions github-actions Bot added the risk: medium PR risk score: medium label Jun 26, 2026
@github-actions

github-actions Bot commented Jun 26, 2026

Copy link
Copy Markdown
Contributor
PR Preview Action v1.8.1

QR code for preview link

🚀 View preview at
https://cli.sentry.dev/_preview/pr-1152/

Built to branch gh-pages at 2026-06-26 22:49 UTC.
Preview will be ready when the GitHub Pages deployment is complete.

Comment thread src/lib/error-reporting.ts
@github-actions

github-actions Bot commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Codecov Results 📊

✅ Patch coverage is 100.00%. Project has 5132 uncovered lines.
✅ Project coverage is 81.47%. Comparing base (base) to head (head).

Coverage diff
@@            Coverage Diff             @@
##          main       #PR       +/-##
==========================================
+ Coverage    81.46%    81.47%    +0.01%
==========================================
  Files          397       397         —
  Lines        27694     27699        +5
  Branches     17983     17989        +6
==========================================
+ Hits         22561     22567        +6
- Misses        5133      5132        -1
- Partials      1861      1862        +1

Generated by Codecov Action

Seer (HIGH) flagged that isNetworkError matched ApiError(status 0), which
is shared by genuine connectivity failures AND TLS certificate errors —
the latter being actionable user-config issues (e.g. a missing CA cert)
that must stay visible. isTlsCertError can't reliably re-detect TLS from
the wrapped ApiError(0), so distinguishing by status is unsafe.

Narrow isNetworkError to ONLY the raw `TypeError: "fetch failed"` (undici's
unambiguous network-failure signature), which is exactly what escapes
uncaught in CLI-16W. ApiError(status 0) — including TLS cert errors — is
no longer treated as a network error and stays captured/actionable.

Revert the handleFetchError conversion (it routed network failures through
ApiError(0), reintroducing the TLS overload); isUserError keeps its
explicit status-0 check so TLS/network ApiErrors still skip the upgrade
nudge. Added a regression test proving TLS ApiError(0) is not silenced.
@BYK BYK changed the title fix: handle network failures gracefully instead of crashing (CLI-16W) fix(error-reporting): stop reporting network fetch failures as crashes (CLI-16W) Jun 26, 2026
@BYK BYK merged commit 76da25b into main Jun 26, 2026
30 checks passed
@BYK BYK deleted the byk/fix/network-error-handling branch June 26, 2026 23:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

risk: medium PR risk score: medium

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant