Skip to content

fix: improve Sentry issue grouping to eliminate duplicate issues#1028

Merged
BYK merged 1 commit into
mainfrom
fix/sentry-issue-dedup
May 27, 2026
Merged

fix: improve Sentry issue grouping to eliminate duplicate issues#1028
BYK merged 1 commit into
mainfrom
fix/sentry-issue-dedup

Conversation

@BYK
Copy link
Copy Markdown
Member

@BYK BYK commented May 27, 2026

Problem

The CLI's Sentry project had 300+ unresolved issues with ~30 duplicate groups caused by gaps in the fingerprinting system:

  1. Missing cli_error.kind tagsCliError (base), HostScopeError, and WizardError had no grouping key, so every unique error message created a separate Sentry issue
  2. Non-CliError exceptions (TypeError, Error, WizardCancelledError) only got cli_error.class with no kind tag
  3. extractResourceKind() didn't strip bare slugs (in my-org) or entity-name prefixed slugs (Organization my-company)
  4. EBADF noise (~2,867 events across 3 duplicate issues) from stdin reopen fd errors
  5. No API endpoint normalization for sub-grouping ApiError by endpoint shape

Solution

Code changes (2 source files)

src/lib/error-reporting.ts:

  • Extract deriveErrorKind() from setGroupingTags() to reduce cognitive complexity
  • Add cli_error.kind for HostScopeError (host_scope), WizardError (wizard), and base CliError (4-word message prefix)
  • Add normalizeEndpoint() — parameterizes variable API path segments, sets cli_error.api_endpoint tag
  • Expand extractResourceKind() — strip in <slug> (not just in org/project), strip hyphenated slugs after entity names
  • Enrich enrichEventWithGroupingTags() — set cli_error.kind from message prefix for non-CliError exceptions

src/lib/telemetry.ts:

  • Add isEbadfError() — detects EBADF errors (bad file descriptor from stdin reopen)
  • Drop EBADF events in beforeSend (same class of OS noise as EPIPE)

Sentry project housekeeping (already done)

  • Merged 18 duplicate groups (~50 issues merged into canonical issues)
  • Resolved 4 issues as resolved in next release (EBADF ×3, replaceAll TypeError ×1)

Tests

  • 34 new tests (unit + property) covering all new grouping logic
  • All 7258 existing tests continue to pass

Expected Impact

Metric Before After
Error classes without cli_error.kind 5 + all non-CliError 0
EBADF events/week ~2,867 0 (dropped)
Duplicate issue groups ~30 0 (merged + prevented)

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 27, 2026

PR Preview Action v1.8.1

QR code for preview link

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

Built to branch gh-pages at 2026-05-27 11:09 UTC.
Preview will be ready when the GitHub Pages deployment is complete.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 27, 2026

Codecov Results 📊

✅ Patch coverage is 94.12%. Project has 4283 uncovered lines.
✅ Project coverage is 82.01%. Comparing base (base) to head (head).

Files with missing lines (2)
File Patch % Lines
src/lib/error-reporting.ts 95.00% ⚠️ 2 Missing and 2 partials
src/lib/telemetry.ts 90.91% ⚠️ 1 Missing and 1 partials
Coverage diff
@@            Coverage Diff             @@
##          main       #PR       +/-##
==========================================
+ Coverage    81.95%    82.01%    +0.06%
==========================================
  Files          329       329         —
  Lines        23749     23805       +56
  Branches     15502     15543       +41
==========================================
+ Hits         19463     19522       +59
- Misses        4286      4283        -3
- Partials      1643      1641        -2

Generated by Codecov Action

@BYK BYK force-pushed the fix/sentry-issue-dedup branch from 5233957 to eec7396 Compare May 27, 2026 10:56
Copy link
Copy Markdown
Contributor

@cursor cursor Bot left a comment

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 2 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 eec7396. Configure here.

const kind = deriveErrorKind(error);
if (kind !== undefined) {
scope.setTag("cli_error.kind", kind);
}
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.

Non-CliError errors through reportCliError miss kind tag

Low Severity

When a non-CliError exception (e.g., TypeError) is routed through reportCliError, deriveErrorKind returns undefined so cli_error.kind is never set on the scope. Then enrichEventWithGroupingTags in beforeSend can't help because its early-return guard sees cli_error.class already present and skips the event — including the new message-prefix logic. The same error type caught by the uncaught-exception handler would get cli_error.kind since cli_error.class isn't pre-set. This contradicts the PR's stated goal of zero error classes without cli_error.kind.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit eec7396. Configure here.

result = result.replace(pattern, replacement);
}
return result.replace(BARE_NUMERIC_SEGMENT_RE, "/{id}");
}
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.

Duplicate exported normalizeEndpoint name across modules

Low Severity

A new exported normalizeEndpoint function is introduced in error-reporting.ts that parameterizes path segments for Sentry grouping, but src/commands/api.ts already exports a completely different normalizeEndpoint that normalizes endpoints for API requests (trailing slashes, prefix stripping). Two exported functions with the same name but very different behavior risk accidental misuse via auto-import.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit eec7396. Configure here.

- Add cli_error.kind tags for CliError, HostScopeError, WizardError
  (previously had no grouping key, every unique message = separate issue)
- Extract deriveErrorKind() from setGroupingTags() to reduce complexity
- Add normalizeEndpoint() for ApiError sub-grouping by endpoint shape
- Expand extractResourceKind() to strip 'in <slug>' and entity name slugs
- Enrich non-CliError exceptions (TypeError, Error) with kind from message
- Drop EBADF errors in beforeSend (same class of OS noise as EPIPE)
- Add 34 new tests (unit + property) covering all new grouping logic
@BYK BYK force-pushed the fix/sentry-issue-dedup branch from eec7396 to 300b2d0 Compare May 27, 2026 11:08
@BYK BYK merged commit 4faf11b into main May 27, 2026
28 checks passed
@BYK BYK deleted the fix/sentry-issue-dedup branch May 27, 2026 11:16
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