-
Notifications
You must be signed in to change notification settings - Fork 15
fix: throw better error when ensrainbow fails to serve json #1713
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
22592cc
9268bbf
610afc3
3b8c13b
7c8f51d
dd8ecdf
94f51a5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -317,30 +317,10 @@ describe("EnsRainbowApiClient", () => { | |
| expect(response).toEqual(configData); | ||
| }); | ||
|
|
||
| it("should throw with server error message when response is not ok", async () => { | ||
| mockFetch.mockResolvedValueOnce({ | ||
| ok: false, | ||
| statusText: "Internal Server Error", | ||
| json: () => | ||
| Promise.resolve({ | ||
| error: "Database not ready", | ||
| errorCode: 500, | ||
| }), | ||
| }); | ||
|
|
||
| await expect(client.config()).rejects.toThrow("Database not ready"); | ||
| }); | ||
|
|
||
| it("should throw with fallback message when error body has no error field", async () => { | ||
| mockFetch.mockResolvedValueOnce({ | ||
| ok: false, | ||
| statusText: "Service Unavailable", | ||
| json: () => Promise.resolve({}), | ||
| }); | ||
| it("should throw with fallback message when error body is not valid JSON", async () => { | ||
| mockFetch.mockResolvedValueOnce({ ok: false, statusText: "Not Found" }); | ||
|
|
||
| await expect(client.config()).rejects.toThrow( | ||
| "Failed to fetch ENSRainbow config: Service Unavailable", | ||
| ); | ||
| await expect(client.config()).rejects.toThrow(/Not Found/); | ||
| }); | ||
|
Comment on lines
+320
to
324
|
||
| }); | ||
| }); | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -400,10 +400,7 @@ export class EnsRainbowApiClient implements EnsRainbow.ApiClient { | |||||||||||||||||||||||||||||||||||||||||||||
| const response = await fetch(new URL("/v1/config", this.options.endpointUrl)); | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| if (!response.ok) { | ||||||||||||||||||||||||||||||||||||||||||||||
| const errorData = (await response.json()) as { error?: string; errorCode?: number }; | ||||||||||||||||||||||||||||||||||||||||||||||
| throw new Error( | ||||||||||||||||||||||||||||||||||||||||||||||
| errorData.error ?? `Failed to fetch ENSRainbow config: ${response.statusText}`, | ||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||
| throw new Error(`Failed to fetch ENSRainbow config: ${response.statusText}`); | ||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||
| throw new Error(`Failed to fetch ENSRainbow config: ${response.statusText}`); | |
| try { | |
| const data: unknown = await response.json(); | |
| if ( | |
| data && | |
| typeof data === "object" && | |
| "error" in data && | |
| typeof (data as { error?: unknown }).error === "string" | |
| ) { | |
| throw new Error((data as { error: string }).error); | |
| } | |
| if (typeof data === "string") { | |
| throw new Error(data); | |
| } | |
| } catch { | |
| // Ignore JSON parsing errors and fall through to generic message | |
| } | |
| const statusText = response.statusText || `status ${response.status}`; | |
| throw new Error(`Failed to fetch ENSRainbow config: ${statusText}`); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Preserve JSON error details before falling back to statusText
Line 403 now always uses statusText, which drops useful server error payloads for valid JSON error responses. This is a behavior regression from the previous error path and makes failures harder to diagnose.
Suggested fix
if (!response.ok) {
- throw new Error(`Failed to fetch ENSRainbow config: ${response.statusText}`);
+ let errorMessage = response.statusText;
+ try {
+ const data = (await response.json()) as { error?: string };
+ if (typeof data.error === "string" && data.error.length > 0) {
+ errorMessage = data.error;
+ }
+ } catch (error) {
+ if (!(error instanceof SyntaxError)) {
+ throw error;
+ }
+ }
+ throw new Error(`Failed to fetch ENSRainbow config: ${errorMessage}`);
}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/ensrainbow-sdk/src/client.ts` around lines 402 - 404, The current
error throw uses only response.statusText and discards any JSON error payload;
update the error path that throws for non-ok responses to read the response body
first and include its details: attempt to parse await response.json() (falling
back to await response.text() if parsing fails), extract a useful message (e.g.,
body.message || body.error || the raw text or JSON stringified body), and then
throw a new Error that includes response.status, response.statusText, and the
extracted error details; reference the existing response variable and the throw
that currently reads `Failed to fetch ENSRainbow config: ${response.statusText}`
and replace it with the richer message as described.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change deletes the existing tests that ensure JSON error bodies are surfaced (server-provided
errorfield) and that the fallback message is used when the JSON body lacks anerrorfield. Ifconfig()is intended to remain compatible with those behaviors (and only add resilience for non-JSON responses), those assertions should remain alongside the new “invalid JSON” test to prevent regressions.