Skip to content

Commit 8777a13

Browse files
committed
fix(project): only diagnose 'org not found' on 404 from listTeams
handleCreateProject404 was treating any listTeams failure as proof that the org doesn't exist. Now it checks the status code: only 404 triggers 'Organization not found'. Other failures (403, 5xx, network) get a generic message that doesn't misdiagnose the root cause.
1 parent d4c1670 commit 8777a13

File tree

2 files changed

+51
-12
lines changed

2 files changed

+51
-12
lines changed

src/commands/project/create.ts

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -115,9 +115,16 @@ async function handleCreateProject404(
115115
name: string,
116116
platform: string
117117
): Promise<never> {
118-
// If listTeams succeeds, the org is valid and the team is wrong
119-
const teams = await listTeams(orgSlug).catch(() => null);
118+
let teams: Awaited<ReturnType<typeof listTeams>> | null = null;
119+
let listTeamsError: unknown = null;
120120

121+
try {
122+
teams = await listTeams(orgSlug);
123+
} catch (error) {
124+
listTeamsError = error;
125+
}
126+
127+
// listTeams succeeded → org is valid, team is wrong
121128
if (teams !== null) {
122129
if (teams.length > 0) {
123130
const teamList = teams.map((t) => ` ${t.slug}`).join("\n");
@@ -134,19 +141,29 @@ async function handleCreateProject404(
134141
);
135142
}
136143

137-
// listTeams also failed — org is likely wrong
138-
let orgHint = `Specify org explicitly: ${USAGE_HINT}`;
139-
try {
140-
const orgs = await listOrganizations();
141-
if (orgs.length > 0) {
142-
const orgList = orgs.map((o) => ` ${o.slug}`).join("\n");
143-
orgHint = `Your organizations:\n\n${orgList}`;
144+
// listTeams returned 404 → org doesn't exist
145+
if (listTeamsError instanceof ApiError && listTeamsError.status === 404) {
146+
let orgHint = `Specify org explicitly: ${USAGE_HINT}`;
147+
try {
148+
const orgs = await listOrganizations();
149+
if (orgs.length > 0) {
150+
const orgList = orgs.map((o) => ` ${o.slug}`).join("\n");
151+
orgHint = `Your organizations:\n\n${orgList}`;
152+
}
153+
} catch {
154+
// Best-effort — if this also fails, use the generic hint
144155
}
145-
} catch {
146-
// Best-effort — if this also fails, use the generic hint
156+
157+
throw new CliError(`Organization '${orgSlug}' not found.\n\n${orgHint}`);
147158
}
148159

149-
throw new CliError(`Organization '${orgSlug}' not found.\n\n${orgHint}`);
160+
// listTeams failed for other reasons (403, 5xx, network) — can't disambiguate
161+
throw new CliError(
162+
`Failed to create project '${name}' in ${orgSlug}.\n\n` +
163+
"The organization or team may not exist, or you may lack access.\n\n" +
164+
"Try:\n" +
165+
` sentry project create ${orgSlug}/${name} ${platform} --team <team-slug>`
166+
);
150167
}
151168

152169
/**

test/commands/project/create.test.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,28 @@ describe("project create", () => {
245245
expect(err.message).toContain("other-org");
246246
});
247247

248+
test("handles 404 with non-404 listTeams failure — shows generic error", async () => {
249+
createProjectSpy.mockRejectedValue(
250+
new ApiError("API request failed: 404 Not Found", 404)
251+
);
252+
// listTeams returns 403 (not 404) — can't tell if org or team is wrong
253+
listTeamsSpy.mockRejectedValue(
254+
new ApiError("API request failed: 403 Forbidden", 403)
255+
);
256+
257+
const { context } = createMockContext();
258+
const func = await createCommand.loader();
259+
260+
const err = await func
261+
.call(context, { json: false, team: "backend" }, "my-app", "node")
262+
.catch((e: Error) => e);
263+
expect(err).toBeInstanceOf(CliError);
264+
expect(err.message).toContain("Failed to create project");
265+
expect(err.message).toContain("may not exist, or you may lack access");
266+
// Should NOT say "Organization not found" — we don't know that
267+
expect(err.message).not.toContain("not found");
268+
});
269+
248270
test("handles 400 invalid platform with platform list", async () => {
249271
createProjectSpy.mockRejectedValue(
250272
new ApiError(

0 commit comments

Comments
 (0)