Skip to content

ErrorBoundary receives the internal { promise } wrapper as loaderData when the route has HydrateFallback #158

Description

@KyleJune

Summary

When a route exports HydrateFallback and has an async loader (a client loader returning a promise, or a server loader), its ErrorBoundary receives Juniper's internal deferred wrapper { promise } as loaderData instead of the loader's data.

Where

src/_client.tsx, createRoute: when HydrateFallback is set, the loader returns { promise: result } (the loader wrapper around line 540). Component unwraps it with <Await resolve={loaderData.promise}>. The ErrorBoundary shim (around line 622) passes useLoaderData() straight through with no unwrap.

Reproduction

With a layout that has HydrateFallback, an async loader and an ErrorBoundary, and a child whose loader throws:

createRoutesStub([{
  path: "/t",
  loader: async () => ({ name: "acme" }),
  HydrateFallback: () => <p>Loading</p>,
  default: () => <Outlet />,
  ErrorBoundary: ({ loaderData }) => <p>{JSON.stringify(Object.keys(loaderData ?? {}))}</p>,
  children: [{ path: "u", loader: () => { throw new Error("x"); }, default: () => <p>U</p> }],
}]);

At /t/u the boundary renders ["promise"]. children on createRoutesStub is the nested-route support in the udibo#975 fix.

Impact

ErrorBoundaryProps<Params, LoaderData>["loaderData"] is typed LoaderData | undefined (after the udibo#979 fix). With this defect the value is a third shape, { promise }. A boundary that checks if (loaderData) and then reads a field gets undefined fields, or crashes on nested access, in the case it exists to handle: a descendant failed while this route's data was fine.

Found

While fixing udibo#979 and udibo#975. It was left out of that PR because it is a change to the boundary shim in src/_client.tsx, not a type or test utility change.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions