Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/lib/error-reporting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ type SilenceReason =
| "output_error"
| "context_missing"
| "auth_expected"
| "validation_error"
| "api_user_error"
| "api_query_error"
| "network_error";
Expand Down Expand Up @@ -91,6 +92,13 @@ export function classifySilenced(error: unknown): SilenceReason | null {
if (error instanceof AuthError) {
return "auth_expected";
}
// A ValidationError means the user supplied malformed input (e.g. a project
// slug where a 32-char hex trace ID was required). It is never a CLI bug —
// the CLI correctly rejects the input and displays an actionable message.
Comment on lines +95 to +97

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Bug: Silencing ValidationError causes reportCliError to return early, which will break new tests in this PR that expect Sentry tags to be set for this error type.
Severity: HIGH

Suggested Fix

The new tests for ValidationError tagging should be removed or modified. Since ValidationError is now intentionally silenced and not reported to Sentry with scope, the tests that assert on its Sentry scope tags are no longer valid. Alternatively, if tagging is still desired, the early return in reportCliError for silenced errors needs to be reconsidered.

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: src/lib/error-reporting.ts#L95-L97

Potential issue: The pull request modifies `classifySilenced` to treat `ValidationError`
as a silenced error. This change causes the `reportCliError` function to return early,
before `Sentry.withScope` is called. However, the PR also introduces new integration
tests that rely on a `capturedScopeTags` helper function. This helper mocks
`Sentry.withScope` to verify that specific tags are set for `ValidationError`. Because
`Sentry.withScope` is no longer invoked for these errors, the tests will receive an
empty set of tags, causing their assertions to fail and breaking the test suite.

Also affects:

  • test/lib/error-reporting.test.ts:492~518

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

// Silence it so it does not pollute Sentry as an unhandled error (CLI-1GP).
if (error instanceof ValidationError) {
return "validation_error";
}
if (error instanceof ApiError && error.status > 400 && error.status < 500) {
return "api_user_error";
}
Expand Down
7 changes: 6 additions & 1 deletion test/lib/error-reporting.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -308,12 +308,17 @@
expect(classifySilenced(err)).toBe("context_missing");
});

test("silences ValidationError (user-supplied malformed input)", () => {
expect(classifySilenced(new ValidationError("bad"))).toBe(
"validation_error",
);
});

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.

Stale ValidationError capture tests

Medium Severity

Silencing ValidationError in classifySilenced makes reportCliError return before withScope, but the integration tests at lines 491–526 still use capturedScopeTags with ValidationError and expect cli_error.* tags from the capture path. Those expectations no longer match behavior and the suite should fail.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 6284299. Configure here.

test.each([
[
"ResolutionError",
new ResolutionError("Project 'x'", "not found", "sentry issue list"),
],
["ValidationError", new ValidationError("bad")],
["SeerError", new SeerError("not_enabled")],
["ConfigError", new ConfigError("bad")],
["generic Error", new Error("boom")],
Expand Down Expand Up @@ -485,7 +490,7 @@

test("ValidationError with field uses field as kind", () => {
const { tags } = capturedScopeTags(new ValidationError("Bad", "trace_id"));
expect(tags["cli_error.class"]).toBe("ValidationError");

Check failure on line 493 in test/lib/error-reporting.test.ts

View workflow job for this annotation

GitHub Actions / Unit Tests

test/lib/error-reporting.test.ts > reportCliError integration > ValidationError with field uses field as kind

AssertionError: expected undefined to be 'ValidationError' // Object.is equality - Expected: "ValidationError" + Received: undefined ❯ test/lib/error-reporting.test.ts:493:37
expect(tags["cli_error.kind"]).toBe("trace_id");
});

Expand All @@ -496,7 +501,7 @@
'Invalid trace ID "d2ad4a2d947b5983". Expected 32-char hex.'
);
const { tags } = capturedScopeTags(err);
expect(tags["cli_error.class"]).toBe("ValidationError");

Check failure on line 504 in test/lib/error-reporting.test.ts

View workflow job for this annotation

GitHub Actions / Unit Tests

test/lib/error-reporting.test.ts > reportCliError integration > ValidationError without field falls back to message prefix

AssertionError: expected undefined to be 'ValidationError' // Object.is equality - Expected: "ValidationError" + Received: undefined ❯ test/lib/error-reporting.test.ts:504:37
expect(tags["cli_error.kind"]).toBe("Invalid trace ID");
});

Expand All @@ -517,7 +522,7 @@
const eventErr = capturedScopeTags(
new ValidationError('Invalid event ID "abc"')
).tags;
expect(traceErr["cli_error.kind"]).not.toBe(eventErr["cli_error.kind"]);

Check failure on line 525 in test/lib/error-reporting.test.ts

View workflow job for this annotation

GitHub Actions / Unit Tests

test/lib/error-reporting.test.ts > reportCliError integration > ValidationError kind differentiates by validator

AssertionError: expected undefined not to be undefined // Object.is equality ❯ test/lib/error-reporting.test.ts:525:44
});

test("captures ResolutionError", () => {
Expand Down
Loading