Skip to content

Commit 2991d9c

Browse files
mattvagniclaude
andauthored
Include GraphQL error messages in HTTP error responses (#15)
When the API returns non-OK HTTP status codes (401, 403, 429, etc.), the client now reads the response body and appends the actual error messages from the GraphQL errors array. This surfaces details like which permissions are missing instead of only showing generic messages. Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 9aa46d7 commit 2991d9c

File tree

1 file changed

+28
-4
lines changed

1 file changed

+28
-4
lines changed

packages/sdk/src/graphql-client.ts

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,16 +56,28 @@ export class PlainGraphQLClient {
5656
});
5757

5858
if (!response.ok) {
59+
const errorDetail = await this.extractErrorMessage(response);
60+
5961
if (response.status === 401) {
60-
throw new AuthenticationError("Invalid API key");
62+
throw new AuthenticationError(
63+
errorDetail ? `Authentication error: ${errorDetail}` : "Authentication error",
64+
);
6165
}
6266
if (response.status === 403) {
63-
throw new ForbiddenError("Insufficient permissions");
67+
throw new ForbiddenError(
68+
errorDetail ? `Insufficient permissions: ${errorDetail}` : "Insufficient permissions",
69+
);
6470
}
6571
if (response.status === 429) {
66-
throw new RateLimitError("Rate limit exceeded");
72+
throw new RateLimitError(
73+
errorDetail ? `Rate limit exceeded: ${errorDetail}` : "Rate limit exceeded",
74+
);
6775
}
68-
throw new NetworkError(`HTTP ${response.status}: ${response.statusText}`);
76+
throw new NetworkError(
77+
errorDetail
78+
? `HTTP ${response.status}: ${response.statusText}: ${errorDetail}`
79+
: `HTTP ${response.status}: ${response.statusText}`,
80+
);
6981
}
7082

7183
const json = (await response.json()) as GraphQLResponse<TData>;
@@ -80,4 +92,16 @@ export class PlainGraphQLClient {
8092

8193
return json.data;
8294
}
95+
96+
private async extractErrorMessage(response: Response): Promise<string | undefined> {
97+
try {
98+
const json = (await response.json()) as GraphQLResponse<unknown>;
99+
if (json.errors && json.errors.length > 0) {
100+
return json.errors.map((e) => e.message).join("; ");
101+
}
102+
} catch {
103+
// Response body wasn't valid JSON — fall back to default message
104+
}
105+
return undefined;
106+
}
83107
}

0 commit comments

Comments
 (0)