diff --git a/.changeset/rare-dodos-push.md b/.changeset/rare-dodos-push.md index 1f312a7d34a..f8154384efa 100644 --- a/.changeset/rare-dodos-push.md +++ b/.changeset/rare-dodos-push.md @@ -2,4 +2,4 @@ "@remix-run/server-runtime": patch --- -Don't log throw redirect response stubs via handleError in Single Fetch +Don't log thrown response stubs via `handleError` in Single Fetch diff --git a/integration/single-fetch-test.ts b/integration/single-fetch-test.ts index 05bbe29d35e..ad0a3cf4fac 100644 --- a/integration/single-fetch-test.ts +++ b/integration/single-fetch-test.ts @@ -1687,7 +1687,7 @@ test.describe("single-fetch", () => { response.headers.set("Location", "/data"); throw response; } - export default function Component() { + export default function Component() { return

Should not see me

; } `, @@ -1705,6 +1705,43 @@ test.describe("single-fetch", () => { expect(errorLogs.length).toBe(0); }); + test("does not log thrown non-redirect response stubs via handleError", async () => { + let fixture = await createFixture({ + config: { + future: { + unstable_singleFetch: true, + }, + }, + files: { + ...files, + "app/routes/redirect.tsx": js` + export function action({ response }) { + response.status = 400; + throw response; + } + export function loader({ response }) { + response.status = 400; + throw response; + } + export default function Component() { + return

Should not see me

; + } + `, + }, + }); + + let errorLogs = []; + console.error = (e) => errorLogs.push(e); + await fixture.requestDocument("/redirect"); + expect(errorLogs.length).toBe(1); // ErrorBoundary render logs this + await fixture.requestSingleFetchData("/redirect.data"); + await fixture.requestSingleFetchData("/redirect.data", { + method: "post", + body: null, + }); + expect(errorLogs.length).toBe(1); + }); + test.describe("client loaders", () => { test("when no routes have client loaders", async ({ page }) => { let fixture = await createFixture( diff --git a/packages/remix-server-runtime/server.ts b/packages/remix-server-runtime/server.ts index f01f6174eb3..e73f7308fb6 100644 --- a/packages/remix-server-runtime/server.ts +++ b/packages/remix-server-runtime/server.ts @@ -40,6 +40,7 @@ import { getSingleFetchDataStrategy, getSingleFetchRedirect, getSingleFetchResourceRouteDataStrategy, + isResponseStub, mergeResponseStubs, singleFetchAction, singleFetchLoaders, @@ -430,7 +431,7 @@ async function handleDocumentRequest( if (context.errors) { Object.values(context.errors).forEach((err) => { // @ts-expect-error `err.error` is "private" from users but intended for internal use - if (!isRouteErrorResponse(err) || err.error) { + if ((!isRouteErrorResponse(err) || err.error) && !isResponseStub(err)) { handleError(err); } }); diff --git a/packages/remix-server-runtime/single-fetch.ts b/packages/remix-server-runtime/single-fetch.ts index bdfe745f7fc..c9303e79be0 100644 --- a/packages/remix-server-runtime/single-fetch.ts +++ b/packages/remix-server-runtime/single-fetch.ts @@ -184,7 +184,7 @@ export async function singleFetchAction( if (context.errors) { Object.values(context.errors).forEach((err) => { // @ts-expect-error This is "private" from users but intended for internal use - if (!isRouteErrorResponse(err) || err.error) { + if ((!isRouteErrorResponse(err) || err.error) && !isResponseStub(err)) { handleError(err); } }); @@ -273,7 +273,7 @@ export async function singleFetchLoaders( if (context.errors) { Object.values(context.errors).forEach((err) => { // @ts-expect-error This is "private" from users but intended for internal use - if (!isRouteErrorResponse(err) || err.error) { + if ((!isRouteErrorResponse(err) || err.error) && !isResponseStub(err)) { handleError(err); } });