Skip to content

Commit ffd9aee

Browse files
committed
feat(cli): pass error code as Sentry tag on captured exceptions
Adds the error code as an `error.code` tag to Sentry exceptions, matching the v1 SentryClient behavior. The code is resolved via resolveErrorCode in both reportError and TaskContextAdapter. Made-with: Cursor
1 parent 924529a commit ffd9aee

File tree

5 files changed

+23
-13
lines changed

5 files changed

+23
-13
lines changed

packages/cli/cli-v2/src/context/adapter/TaskContextAdapter.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {
55
type Finishable,
66
type InteractiveTaskContext,
77
type PosthogEvent,
8+
resolveErrorCode,
89
type Startable,
910
TaskAbortSignal,
1011
type TaskContext,
@@ -68,8 +69,9 @@ export class TaskContextAdapter implements TaskContext {
6869
reportError(this.context, error ?? new Error(message), options);
6970
}
7071

71-
public captureException(error: unknown, _code?: CliError.Code): void {
72-
this.context.telemetry.captureException(error);
72+
public captureException(error: unknown, code?: CliError.Code): void {
73+
const errorCode = resolveErrorCode(error, code) ?? "INTERNAL_ERROR";
74+
this.context.telemetry.captureException(error, { errorCode });
7375
}
7476

7577
private getFullErrorMessage(message?: string, error?: unknown): string | undefined {

packages/cli/cli-v2/src/context/withContext.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ export function reportError(context: Context, error: unknown, options?: { code?:
114114
}
115115
const code = resolveErrorCode(error, options?.code) ?? "INTERNAL_ERROR";
116116
if (shouldReportToSentry(code)) {
117-
context.telemetry.captureException(error);
117+
context.telemetry.captureException(error, { errorCode: code });
118118
}
119119
context.telemetry.sendLifecycleEvent({
120120
status: "error",

packages/cli/cli-v2/src/telemetry/TelemetryClient.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,15 +105,15 @@ export class TelemetryClient {
105105
* The caller is responsible for deciding which errors are worth reporting
106106
* (see `shouldReportToSentry` in withContext.ts).
107107
*/
108-
public captureException(error: unknown): void {
108+
public captureException(error: unknown, { errorCode }: { errorCode: string }): void {
109109
if (this.sentry === undefined) {
110110
return;
111111
}
112112
try {
113113
this.sentry.captureException(error, {
114114
captureContext: {
115115
user: { id: this.distinctId },
116-
tags: { ...this.baseTags, ...this.accumulatedTags }
116+
tags: { ...this.baseTags, ...this.accumulatedTags, "error.code": errorCode }
117117
}
118118
});
119119
} catch {

packages/cli/cli/src/telemetry/SentryClient.ts

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,14 +27,10 @@ export class SentryClient {
2727
return;
2828
}
2929
try {
30-
if (code != null) {
31-
Sentry.withScope((scope) => {
32-
scope.setTag("error.code", code);
33-
this.sentry?.captureException(error);
34-
});
35-
} else {
36-
this.sentry.captureException(error);
37-
}
30+
this.sentry.captureException(
31+
error,
32+
code != null ? { captureContext: { tags: { "error.code": code } } } : undefined
33+
);
3834
} catch {
3935
// no-op
4036
}

packages/cli/cli/src/telemetry/__test__/SentryClient.test.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,18 @@ describe("SentryClient (cli-v1)", () => {
5050

5151
expect(mockSentryInit).toHaveBeenCalledOnce();
5252
expect(mockSentryCaptureException).toHaveBeenCalledOnce();
53+
expect(mockSentryCaptureException).toHaveBeenCalledWith(expect.any(Error), undefined);
54+
});
55+
56+
it("passes error.code tag via captureContext when code is provided", () => {
57+
const client = new SentryClient({ release: "cli@1.2.3" });
58+
const error = new Error("something broke");
59+
60+
client.captureException(error, "INTERNAL_ERROR");
61+
62+
expect(mockSentryCaptureException).toHaveBeenCalledWith(error, {
63+
captureContext: { tags: { "error.code": "INTERNAL_ERROR" } }
64+
});
5365
});
5466

5567
it("flushes the Sentry client", async () => {

0 commit comments

Comments
 (0)