Skip to content

Commit b74d1d6

Browse files
authored
fix: add actionable suggestions for 400 Bad Request on issue list (CLI-BM, CLI-7B) (#489)
## Problem When `sentry issue list` gets a 400 Bad Request from the API, the error shows the raw API detail but doesn't guide users on what to fix. This is the most common API error class, affecting **93 users** across [CLI-BM](https://sentry.sentry.io/issues/7315010148/) (55 users) and [CLI-7B](https://sentry.sentry.io/issues/7277810245/) (38 users). Common causes include: - Invalid Sentry search query syntax (e.g., unparenthesized OR operators) - Default `--period 90d` exceeding plan data retention - Project access issues ## Fix Added a `build400Detail()` helper that enriches the 400 error detail with context-aware suggestions based on the current command flags: **When `--query` is provided:** ``` Failed to fetch issues from 1 project(s): Failed to list issues: 400 Bad Request Invalid search query: ... Suggestions: • Check your --query syntax (Sentry search reference: https://docs.sentry.io/concepts/search/) • Try a shorter time range: --period 14d or --period 24h • Verify you have access to the target project: sentry project list <org>/ ``` **When using default period (no --query):** ``` Failed to fetch issues from 1 project(s): Failed to list issues: 400 Bad Request ... Suggestions: • Try a shorter time range: --period 14d or --period 24h • Verify you have access to the target project: sentry project list <org>/ ``` ## Design Decisions - Suggestions are **appended after** the original API detail so the specific error reason is shown first - The query syntax suggestion only appears when `--query` is actually used - The period suggestion only appears when using the default 90d (users who explicitly set a period likely don't need this hint) - The `build400Detail` function is intentionally narrow-scoped to 400 errors to avoid cluttering other error types
1 parent a26e3f4 commit b74d1d6

File tree

1 file changed

+64
-2
lines changed

1 file changed

+64
-2
lines changed

src/commands/issue/list.ts

Lines changed: 64 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -892,6 +892,61 @@ type ResolvedTargetsOptions = {
892892
setContext: (orgs: string[], projects: string[]) => void;
893893
};
894894

895+
/** Default --period value (used to detect user-implicit vs explicit). */
896+
const DEFAULT_PERIOD = "90d";
897+
898+
/**
899+
* Build an enriched error detail for 400 Bad Request responses.
900+
*
901+
* Appends actionable suggestions so users know what to try next. This is the
902+
* most common class of API error in `issue list` (CLI-BM, CLI-7B) — the Sentry
903+
* API rejects the request due to query syntax or parameter issues, but the raw
904+
* "400 Bad Request" message alone doesn't guide the user to a fix.
905+
*
906+
* @param originalDetail - The API response detail (may be undefined)
907+
* @param flags - Current command flags for context-aware hints
908+
* @returns Enhanced detail string with suggestions
909+
*/
910+
function build400Detail(
911+
originalDetail: string | undefined,
912+
flags: Pick<ListFlags, "query" | "period">
913+
): string {
914+
const lines: string[] = [];
915+
916+
if (originalDetail) {
917+
lines.push(originalDetail);
918+
}
919+
920+
const suggestions: string[] = [];
921+
922+
if (flags.query) {
923+
suggestions.push(
924+
"Check your --query syntax (Sentry search reference: https://docs.sentry.io/concepts/search/)"
925+
);
926+
}
927+
928+
if (!flags.period || flags.period === DEFAULT_PERIOD) {
929+
suggestions.push("Try a shorter time range: --period 14d or --period 24h");
930+
}
931+
932+
suggestions.push(
933+
"Verify you have access to the target project: sentry project list <org>/"
934+
);
935+
936+
// Only add the separator when there's a detail line preceding the suggestions
937+
if (lines.length > 0) {
938+
lines.push("");
939+
}
940+
lines.push("Suggestions:");
941+
for (const s of suggestions) {
942+
lines.push(` • ${s}`);
943+
}
944+
945+
// ApiError.format() prepends "\n " only before the first line of detail.
946+
// Indent continuation lines to maintain alignment with the first line.
947+
return lines.join("\n ");
948+
}
949+
895950
/**
896951
* Handle auto-detect, explicit, and project-search modes.
897952
*
@@ -1039,12 +1094,19 @@ async function handleResolvedTargets(
10391094
const { error: first } = failures[0]!;
10401095
const prefix = `Failed to fetch issues from ${targets.length} project(s)`;
10411096

1042-
// Propagate ApiError so telemetry sees the original status code
1097+
// Propagate ApiError so telemetry sees the original status code.
1098+
// For 400 errors, append actionable suggestions since the user's query
1099+
// or parameters are likely malformed. Common causes: invalid Sentry
1100+
// search syntax, unsupported period for the org's data retention.
10431101
if (first instanceof ApiError) {
1102+
const detail =
1103+
first.status === 400
1104+
? build400Detail(first.detail, flags)
1105+
: first.detail;
10441106
throw new ApiError(
10451107
`${prefix}: ${first.message}`,
10461108
first.status,
1047-
first.detail,
1109+
detail,
10481110
first.endpoint
10491111
);
10501112
}

0 commit comments

Comments
 (0)