Skip to content

Pending spinner + throw redirect = MatchInnerImpl error #7367

Closed

Description

@piscopancer

Describe the bug

Hey, I want to know why there's component race condition for a pending component when i throw redirects. The logic's simple - show a spinner for good looks right away, but check the user role in the background - then redirect to their dedicated routes

// __root.tsx
export const Route = createRootRouteWithContext<RouterContext>()({
  component: RootComponent,
  pendingMs: 0, // show spinnner immediately - error when `beforeLoad` is over. Set it to `1000` - no error
  pendingMinMs: 500,
  pendingComponent: () => {
    return <SpinnerScreen />;
  },
  errorComponent: (props) => <pre>{JSON.stringify(props.error, null, 2)}</pre>,
  async beforeLoad({ context, location }) {
    const user = await context.qc.ensureQueryData(sessionQueryOptions);
    if (location.pathname.startsWith(WelcomeRoute.to)) return;
    const redir = match(user.type)
      .with("edit_op", () =>
        !location.pathname.startsWith(EditSalesRoute.to)
          ? redirect({
              to: EditSalesRoute.to,
              replace: true,
            })
          : undefined,
      )
      .with(...)
      .exhaustive();
    if (redir) throw redir;
  },
});
Image

and you can see a white screen
when i reload the page it will be normal
when i set pendingMs to a 1000, a spinner will not show up but the error will be gone, luckily
though i need a spinner right away

Your minimal, reproducible example

Steps to reproduce

Expected behavior

No react dom error must appear

How often does this bug happen?

None

Screenshots or Videos

No response

Platform

Windows 10, Zen browser latest

Tanstack Query adapter

None

TanStack Query version

5.90.12

TypeScript version

5.9.3

Additional context

No response

Activity

  1. transferred this issue fromTanStack/queryon May 8, 2026
  2. codeart1st commented on May 8, 2026

    @codeart1st

    It's probably the same as my issue #7120

  3. piscopancer commented on May 8, 2026

    @piscopancer
    Author

    It's probably the same as my issue #7120

    And did you find a solution? Currently, I think it's a bug and I even wanted to update the package.

    Also I don't find any other neat way to render a spinner because beforeLoad prevents react from rendering

  4. piscopancer commented on May 9, 2026

    @piscopancer
    Author

    any update on this?

  5. melv-n commented on May 12, 2026

    @melv-n
    Contributor

    #7158 aims to address #7120

  6. piscopancer commented on May 12, 2026

    @piscopancer
    Author

    #7158 aims to address #7120

    So there is no fix yet?

  7. schiller-manuel commented on May 12, 2026

    @schiller-manuel
    Collaborator

    you did not provide a minimal complete reproducer. please do so.

  8. piscopancer commented on May 12, 2026

    @piscopancer
    Author

    you did not provide a minimal complete reproducer. please do so.

    But my explanation seems to be enough. I throughly explained what I did. BeforeLoad + waiting a server fetch inside. Then redirect. In the meanwhile, rendering a pending component, when redirect thrown - error. If pendingComponent was not provided - fine

  9. piscopancer commented on May 12, 2026

    @piscopancer
    Author

    If you insist I can create a repo but it will take time, is it this necessary then?

  10. talelmishali commented on May 12, 2026

    @talelmishali

    @schiller-manuel By the way, even when throwing a redirect on beforeLoad getting the same results - needs a separate issue or you think it will be covered?

  11. rkorobchuk commented on Jun 5, 2026

    @rkorobchuk

    @schiller-manuel I'm experiencing this crash with @tanstack/react-router@1.170.11 / @tanstack/router-core@1.171.9 on React 19.
    Setup: defaultPendingComponent is configured (default pendingMs: 1000). Root route's beforeLoad does several async calls (auth, user data, settings) that take >1000ms on cold page load. A child route's beforeLoad throws redirect().
    Maybe this could help (Used AI to determine what happened)
    What happens:

    1. setupPendingTimeout fires after 1000ms, calls triggerOnReady(), which commits all pending matches (including the child) to React
    2. Root's beforeLoad finishes, child's beforeLoad runs and throws redirect
    3. handleRedirectAndNotFound sets the already-committed child match to status: "redirected" and resolves its loadPromise
    4. MatchInnerImpl (already rendering) hits if (match.status === "redirected") { throw getMatchPromise(match, "loadPromise") } — throws an already-resolved ControlledPromise
    5. React Suspense can't handle a thenable with status: "resolved" (it expects "fulfilled") → infinite render loop → Uncaught undefined

    Without pendingComponent the setupPendingTimeout condition is false → timeout never fires → matches aren't committed prematurely → no crash.

  12. schiller-manuel commented on Jun 5, 2026

    @schiller-manuel
    Collaborator

    @rkorobchuk there is still no complete minimal reproducer project available

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

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions