Skip to content
Open
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
57 changes: 40 additions & 17 deletions src/commands/span/view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,30 +99,53 @@ export function parsePositionalArgs(args: string[]): SpanViewArgs {
throw new ContextError("Trace ID and span ID", USAGE_HINT, []);
}

// Auto-detect `<trace-id>/<span-id>` single-arg form. When a single
// arg contains exactly one slash separating a 32-char hex trace ID
// from a 16-char hex span ID, the user clearly intended to pass both.
// Auto-detect `[<org>/<project>/]<trace-id>/<span-id>` single-arg form.
// The user clearly intended to pass both trace target and span ID together.
// We split on the last slash so that full `org/project/trace-id/span-id`
// inputs are handled correctly, not just the simple `trace-id/span-id` form.
// Without this check, parseSlashSeparatedTraceTarget treats the span
// ID as a trace ID and fails validation (CLI-G6).
if (args.length === 1) {
const slashIdx = first.indexOf("/");
if (slashIdx !== -1 && first.indexOf("/", slashIdx + 1) === -1) {
const left = normalizeHexId(first.slice(0, slashIdx));
const lastSlashIdx = first.lastIndexOf("/");
if (lastSlashIdx !== -1) {
const right = first
.slice(slashIdx + 1)
.slice(lastSlashIdx + 1)
.trim()
.toLowerCase()
.replace(/-/g, "");
if (HEX_ID_RE.test(left) && SPAN_ID_RE.test(right)) {
log.warn(
`Interpreting '${first}' as <trace-id>/<span-id>. ` +
`Use separate arguments: sentry span view ${left} ${right}`
);
return {
kind: "resolved",
traceTarget: { type: "auto-detect" as const, traceId: left },
rawSpanIds: [right],
};
if (SPAN_ID_RE.test(right)) {
const rawLeft = first.slice(0, lastSlashIdx);
const firstSlashIdx = first.indexOf("/");
const hasMultipleSlashes = firstSlashIdx !== lastSlashIdx;

if (hasMultipleSlashes) {
// Multi-segment form: org/project/trace-id/span-id — defer so that
// parseTraceTargetWithRecovery resolves the full trace target.
log.warn(
`Interpreting '${first}' as <trace-target>/<span-id>. ` +
`Use separate arguments: sentry span view ${rawLeft} ${right}`
);
return {
kind: "deferred",
rawTraceArg: rawLeft,
rawSpanIds: [right],
};
Comment on lines +122 to +132

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: The new multi-slash handling logic incorrectly parses arguments like org/project/span-id, leading to a confusing error about an invalid trace ID instead of a missing span ID.
Severity: MEDIUM

Suggested Fix

Add validation to the hasMultipleSlashes branch to ensure that arguments like org/project/span-id are parsed correctly. The logic should be similar to the single-slash branch, ensuring that the components are correctly identified as organization, project, and span ID, and provide a clear error if the format is invalid.

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/commands/span/view.ts#L121-L132

Potential issue: The logic for handling arguments with multiple slashes, such as
`org/project/span-id`, incorrectly splits the input. It treats `org/project` as the
trace target and `span-id` as the span ID. This causes `parseTraceTargetWithRecovery` to
attempt to validate `project` as a trace ID, which fails and produces a confusing
`ValidationError: Invalid trace ID "project"`. This is a regression from the previous
behavior, which would have correctly identified that a span ID was missing and provided
a clearer error message. The new `hasMultipleSlashes` branch lacks the necessary
validation to prevent this incorrect parsing.

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

} else {
// Simple trace-id/span-id form: left must be a valid 32-char hex
// trace ID. If not, fall through to the missing-span-IDs error.
const left = normalizeHexId(rawLeft);
if (HEX_ID_RE.test(left)) {
log.warn(
`Interpreting '${first}' as <trace-id>/<span-id>. ` +
`Use separate arguments: sentry span view ${left} ${right}`
);
return {
kind: "resolved",
traceTarget: { type: "auto-detect" as const, traceId: left },
rawSpanIds: [right],
};
}
}
}
}
}
Expand Down
Loading