Skip to content

fix(router-core): fix handle AbortError logic when rapid navigation - #6426

Merged
nlynzaad merged 8 commits into
TanStack:mainfrom
leesb971204:fix/rapid-navigation-abort-error
Feb 5, 2026
Merged

fix(router-core): fix handle AbortError logic when rapid navigation#6426
nlynzaad merged 8 commits into
TanStack:mainfrom
leesb971204:fix/rapid-navigation-abort-error

Conversation

@leesb971204

@leesb971204leesb971204 commented Jan 20, 2026

Copy link
Copy Markdown
Contributor

fixes#6388

Summary

  • Fixed a bug where rapid navigation between parameterized routes caused errorComponent to render incorrectly

Problem

When rapidly navigating between parameterized routes (e.g., /something/1 → /something/2 → /something/1), the errorComponent was incorrectly triggered with a TypeError.

Root cause: The existing AbortError handler set status: 'success' without setting loaderData. When the component tried to access loaderData, it was undefined, causing a TypeError that was caught by the error boundary.

Solution

Distinguish between two types of AbortError by checking abortController.signal.aborted:

AbortError Typesignal.abortedHandling
Intentional (loader throws AbortError directly)falseOriginal behavior (set status to 'success')
Navigation abort (cancelMatches triggered)trueDon't update match state, only resolve loaderPromise

Additionally, after awaiting a previous loaderPromise, check if the match status is still 'pending'. If so, the previous loader was aborted and a fresh loader needs to run.

Summary by CodeRabbit

  • Bug Fixes

    • Fixed rapid navigation between parameterized routes so aborted loads no longer trigger error UI and final route renders reliably.
  • Tests

    • Added an end-to-end test reproducer validating rapid param-route navigation does not show error components.
    • Updated existing navigation store-update tests to reflect corrected update counts during navigation.

✏️ Tip: You can customize this high-level summary in your review settings.

Signed-off-by: leesb971204 <leesb971204@gmail.com>
@coderabbitai

coderabbitaiBot commented Jan 20, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Refines loader abort/error handling to distinguish navigation-caused aborts and avoid spurious errorComponent renders; adds an end-to-end test reproducer that rapidly navigates parameterized routes to validate the fix.

Changes

Cohort / File(s)Summary
E2E test reproducer
packages/react-router/tests/loaders.test.tsx
Adds an end-to-end test that rapidly navigates between parameterized routes, using an AbortController-managed loader and an errorComponent spy to assert no erroneous error renders and that the latest loader completes.
Loader abort & post-wait logic
packages/router-core/src/load-matches.ts
Adjusts AbortError handling to detect navigation-caused aborts (treating them differently from other aborts), clears/resolves loaderPromise appropriately, and uses the awaited match state (matchAfterWait) with an early return if it's no longer pending to prevent stale continuation.
Minor test expectation updates
packages/react-router/tests/store-updates-during-navigation.test.tsx
Increases expected store update counts from 7 → 8 in two tests to reflect adjusted update behavior during navigation.

Sequence Diagram(s)

mermaid
sequenceDiagram
participant Client
participant RouterCore as Router-Core
participant Loader as Loader (with AbortController)
participant MatchStore as Match State

Client->>RouterCore: navigate to /something/1
RouterCore->>Loader: start loader (attach AbortController)
Loader-->>RouterCore: pending result / can be aborted
Client->>RouterCore: rapid navigate to /something/2
RouterCore->>Loader: abort previous loader (navigation-caused)
RouterCore->>MatchStore: mark previous match as aborted/clear loaderPromise
RouterCore->>Loader: start new loader for /something/2
Loader-->>RouterCore: resolves successfully
RouterCore->>MatchStore: commit success for latest match (no errorComponent render)
Client->>RouterCore: navigate back to /something/1
RouterCore->>Loader: start loader for /something/1
Loader-->>RouterCore: resolves successfully
RouterCore->>MatchStore: commit success for latest match (final render)

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

Suggested reviewers

  • schiller-manuel
  • nlynzaad

Poem

🐰
Quick hops between params, I prance,
Aborts now know to yield their chance.
Pending stays until the right one lands,
No false alarms across the lands —
Hooray, smooth routes and steady hands! ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title accurately describes the main change: fixing AbortError handling logic during rapid navigation, which is the core objective of this PR.
Linked Issues check✅ PassedThe PR addresses all coding requirements from issue #6388: distinguishes abort cases, prevents errorComponent rendering, ensures proper match status during rapid navigation, and validates with a comprehensive reproducer test.
Out of Scope Changes check✅ PassedAll changes are directly related to fixing the rapid navigation abort handling issue. The test updates reflect the expected behavior changes from the core logic fixes.
Docstring Coverage✅ PassedNo functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Comment @coderabbitai help to get the list of available commands and usage tips.

@leesb971204leesb971204 changed the title fix(router-core): fix handle AbortError logicfix(router-core): fix handle AbortError logic when rapid navigationJan 20, 2026
@nx-cloud

nx-cloudBot commented Jan 20, 2026

Copy link
Copy Markdown
Contributor

View your CI Pipeline Execution ↗ for commit f2708c1

CommandStatusDurationResult
nx affected --targets=test:eslint,test:unit,tes...✅ Succeeded1m 58sView ↗
nx run-many --target=build --exclude=examples/*...✅ Succeeded2sView ↗

☁️ Nx Cloud last updated this comment at 2026-02-05 01:37:16 UTC

@pkg-pr-new

pkg-pr-newBot commented Jan 20, 2026

Copy link
Copy Markdown
More templates

@tanstack/arktype-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/arktype-adapter@6426

@tanstack/eslint-plugin-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/eslint-plugin-router@6426

@tanstack/history

npm i https://pkg.pr.new/TanStack/router/@tanstack/history@6426

@tanstack/nitro-v2-vite-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/nitro-v2-vite-plugin@6426

@tanstack/react-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router@6426

@tanstack/react-router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router-devtools@6426

@tanstack/react-router-ssr-query

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router-ssr-query@6426

@tanstack/react-start

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start@6426

@tanstack/react-start-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-client@6426

@tanstack/react-start-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-server@6426

@tanstack/router-cli

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-cli@6426

@tanstack/router-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-core@6426

@tanstack/router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-devtools@6426

@tanstack/router-devtools-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-devtools-core@6426

@tanstack/router-generator

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-generator@6426

@tanstack/router-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-plugin@6426

@tanstack/router-ssr-query-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-ssr-query-core@6426

@tanstack/router-utils

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-utils@6426

@tanstack/router-vite-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-vite-plugin@6426

@tanstack/solid-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router@6426

@tanstack/solid-router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router-devtools@6426

@tanstack/solid-router-ssr-query

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router-ssr-query@6426

@tanstack/solid-start

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start@6426

@tanstack/solid-start-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-client@6426

@tanstack/solid-start-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-server@6426

@tanstack/start-client-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-client-core@6426

@tanstack/start-fn-stubs

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-fn-stubs@6426

@tanstack/start-plugin-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-plugin-core@6426

@tanstack/start-server-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-core@6426

@tanstack/start-static-server-functions

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-static-server-functions@6426

@tanstack/start-storage-context

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-storage-context@6426

@tanstack/valibot-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/valibot-adapter@6426

@tanstack/virtual-file-routes

npm i https://pkg.pr.new/TanStack/router/@tanstack/virtual-file-routes@6426

@tanstack/vue-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/vue-router@6426

@tanstack/vue-router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/vue-router-devtools@6426

@tanstack/vue-router-ssr-query

npm i https://pkg.pr.new/TanStack/router/@tanstack/vue-router-ssr-query@6426

@tanstack/vue-start

npm i https://pkg.pr.new/TanStack/router/@tanstack/vue-start@6426

@tanstack/vue-start-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/vue-start-client@6426

@tanstack/vue-start-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/vue-start-server@6426

@tanstack/zod-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/zod-adapter@6426

commit: f2708c1

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@packages/router-core/src/load-matches.ts`:
- Around line 783-792: In loadRouteMatch ensure any pending timeout set during
this load cycle is cleared before the early return: if you created a
pendingTimeout (e.g., pendingTimeout or inner.pendingTimeout) clear it with
clearTimeout(...) and reset the variable (e.g., pendingTimeout = undefined or
inner.pendingTimeout = undefined) immediately before returning when
matchAfterWait.status !== 'pending'; do this near the block that reads
matchAfterWait and calls handleRedirectAndNotFound so pending timers don't
persist and block future pending scheduling.
🧹 Nitpick comments (1)
packages/react-router/tests/loaders.test.tsx (1)

828-936: Tighten final-state assertions to avoid false positives.

Right now the test passes as long as some param page renders and the loader completes. Consider asserting the final param value and expected loader completion id to make the repro more specific (Line 933-936).

♻️ Suggested test assertion enhancement
 const paramPage = await screen.findByTestId('param-page')
expect(paramPage).toBeInTheDocument()
- expect(loaderCompleteMock).toHaveBeenCalled()+ expect(paramPage).toHaveTextContent('Param Component 1')+ expect(loaderCompleteMock).toHaveBeenCalledWith('1')

Comment threadpackages/router-core/src/load-matches.ts Outdated
Signed-off-by: leesb971204 <leesb971204@gmail.com>
@leesb971204

Copy link
Copy Markdown
ContributorAuthor

@schiller-manuel
can you please review this?

@leesb971204

Copy link
Copy Markdown
ContributorAuthor

@nlynzaad
can you please review this? I think manuel is too busy now.

@nlynzaad

nlynzaad commented Feb 5, 2026

Copy link
Copy Markdown
Contributor

@leesb971204 thanks for this.

I had a look and my only real concern was the change in the control flow on loadRouteMatch.

I've merged with main and made some changes (most just isolating the running of the loader) to address the above.

Comment threadpackages/solid-router/tests/link.test.tsx
Comment threadpackages/solid-router/tests/link.test.tsx
Comment threadpackages/vue-router/tests/link.test.tsx
@nlynzaad
nlynzaad merged commit 28b0e8b into TanStack:mainFeb 5, 2026
6 checks passed
@leesb971204

Copy link
Copy Markdown
ContributorAuthor

@leesb971204 thanks for this.

I had a look and my only real concern was the change in the control flow on loadRouteMatch.

I've merged with main and made some changes (most just isolating the running of the loader) to address the above.

Awesome! Thnks for this!

Sheraff pushed a commit that referenced this pull request Feb 15, 2026
…6426)
* fix(router-core): fix handle AbortError logic
Signed-off-by: leesb971204 <leesb971204@gmail.com>
* ci: apply automated fixes
* test: update expected store update count for preloaded async loaders
Signed-off-by: leesb971204 <leesb971204@gmail.com>
* refractor changes
* update tests to handle wait times more appropriately
* tighten up test - coderabbit nitpick
---------
Signed-off-by: leesb971204 <leesb971204@gmail.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Nico Lynzaad <nlynzaad@zylangroup.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Aborted loader request renders errorComponent and on rapid param navigation with undefined error

2 participants

@leesb971204@nlynzaad