diff --git a/.changeset/catch-unwrap-error.md b/.changeset/catch-unwrap-error.md new file mode 100644 index 0000000000..1a89d4b35c --- /dev/null +++ b/.changeset/catch-unwrap-error.md @@ -0,0 +1,5 @@ +--- +"@remix-run/router": patch +--- + +Catch and bubble errors thrown when trying to unwrap responses from `loader`/`action` functions diff --git a/packages/router/__tests__/navigation-test.ts b/packages/router/__tests__/navigation-test.ts index fc99d9a4a7..f4bffc592e 100644 --- a/packages/router/__tests__/navigation-test.ts +++ b/packages/router/__tests__/navigation-test.ts @@ -124,6 +124,75 @@ describe("navigations", () => { }); }); + it("handles errors when unwrapping Responses", async () => { + let t = setup({ + routes: [ + { + path: "/", + children: [ + { + id: "foo", + path: "foo", + hasErrorBoundary: true, + loader: true, + }, + ], + }, + ], + }); + let A = await t.navigate("/foo"); + await A.loaders.foo.resolve( + // Invalid JSON + new Response('{"key":"value"}}}}}', { + status: 200, + headers: { + "Content-Type": "application/json", + }, + }) + ); + expect(t.router.state.loaderData).toEqual({}); + expect(t.router.state.errors).toMatchInlineSnapshot(` + { + "foo": [SyntaxError: Unexpected token } in JSON at position 15], + } + `); + }); + + it("bubbles errors when unwrapping Responses", async () => { + let t = setup({ + routes: [ + { + id: "root", + path: "/", + hasErrorBoundary: true, + children: [ + { + id: "foo", + path: "foo", + loader: true, + }, + ], + }, + ], + }); + let A = await t.navigate("/foo"); + await A.loaders.foo.resolve( + // Invalid JSON + new Response('{"key":"value"}}}}}', { + status: 200, + headers: { + "Content-Type": "application/json", + }, + }) + ); + expect(t.router.state.loaderData).toEqual({}); + expect(t.router.state.errors).toMatchInlineSnapshot(` + { + "root": [SyntaxError: Unexpected token } in JSON at position 15], + } + `); + }); + it("does not fetch unchanging layout data", async () => { let t = initializeTest(); let A = await t.navigate("/foo"); diff --git a/packages/router/router.ts b/packages/router/router.ts index 21453256af..7eacf42291 100644 --- a/packages/router/router.ts +++ b/packages/router/router.ts @@ -3990,13 +3990,18 @@ async function callLoaderOrAction( } let data: any; - let contentType = result.headers.get("Content-Type"); - // Check between word boundaries instead of startsWith() due to the last - // paragraph of https://httpwg.org/specs/rfc9110.html#field.content-type - if (contentType && /\bapplication\/json\b/.test(contentType)) { - data = await result.json(); - } else { - data = await result.text(); + + try { + let contentType = result.headers.get("Content-Type"); + // Check between word boundaries instead of startsWith() due to the last + // paragraph of https://httpwg.org/specs/rfc9110.html#field.content-type + if (contentType && /\bapplication\/json\b/.test(contentType)) { + data = await result.json(); + } else { + data = await result.text(); + } + } catch (e) { + return { type: ResultType.error, error: e }; } if (resultType === ResultType.error) {