From bd633ce187ecade0c55ad07b2e76189d099473a9 Mon Sep 17 00:00:00 2001
From: leesb971204 <leesb971204@gmail.com>
Date: Tue, 6 Jan 2026 11:40:12 +0900
Subject: [PATCH 1/2] fix(router-core): handle AbortError in router execution
 flow

Signed-off-by: leesb971204 <leesb971204@gmail.com>
---
 packages/react-router/tests/loaders.test.tsx | 29 +++++++++++++++++++-
 packages/router-core/src/load-matches.ts     | 10 +++++++
 packages/solid-router/tests/loaders.test.tsx | 27 ++++++++++++++++++
 3 files changed, 65 insertions(+), 1 deletion(-)

diff --git a/packages/react-router/tests/loaders.test.tsx b/packages/react-router/tests/loaders.test.tsx
index 8d8ea54e73..fc9e87b077 100644
--- a/packages/react-router/tests/loaders.test.tsx
+++ b/packages/react-router/tests/loaders.test.tsx
@@ -430,7 +430,7 @@ test('reproducer #4546', async () => {
     component: () => {
       return (
         <>
-          <div className="p-2 flex gap-2 text-lg">
+          <div className="flex gap-2 p-2 text-lg">
             <Link
               data-testid="link-to-index"
               to="/"
@@ -730,6 +730,33 @@ test('clears pendingTimeout when match resolves', async () => {
   expect(fooPendingComponentOnMountMock).not.toHaveBeenCalled()
 })
 
+test('throw abortError from loader upon initial load with basepath', async () => {
+  window.history.replaceState(null, 'root', '/app')
+  const rootRoute = createRootRoute({})
+
+  const indexRoute = createRoute({
+    getParentRoute: () => rootRoute,
+    path: '/',
+    loader: async () => {
+      return Promise.reject(new DOMException('Aborted', 'AbortError'))
+    },
+    component: () => <div>Index route content</div>,
+    errorComponent: () => (
+      <div data-testid="index-error">indexErrorComponent</div>
+    ),
+  })
+
+  const routeTree = rootRoute.addChildren([indexRoute])
+  const router = createRouter({ routeTree, history, basepath: '/app' })
+
+  render(<RouterProvider router={router} />)
+
+  const indexElement = await screen.findByText('Index route content')
+  expect(indexElement).toBeInTheDocument()
+  expect(screen.queryByTestId('index-error')).not.toBeInTheDocument()
+  expect(window.location.pathname.startsWith('/app')).toBe(true)
+})
+
 test('cancelMatches after pending timeout', async () => {
   function getPendingComponent(onMount: () => void) {
     const PendingComponent = () => {
diff --git a/packages/router-core/src/load-matches.ts b/packages/router-core/src/load-matches.ts
index ec72cbfe44..9d3a4b0aeb 100644
--- a/packages/router-core/src/load-matches.ts
+++ b/packages/router-core/src/load-matches.ts
@@ -699,6 +699,16 @@ const runLoader = async (
     } catch (e) {
       let error = e
 
+      if (error instanceof DOMException && error.name === 'AbortError') {
+        const head = await executeHead(inner, matchId, route)
+        inner.updateMatch(matchId, (prev) => ({
+          ...prev,
+          status: prev.status === 'pending' ? 'success' : prev.status,
+          ...head,
+        }))
+        return
+      }
+
       const pendingPromise = match._nonReactive.minPendingPromise
       if (pendingPromise) await pendingPromise
 
diff --git a/packages/solid-router/tests/loaders.test.tsx b/packages/solid-router/tests/loaders.test.tsx
index c0e5253219..09f1676bd8 100644
--- a/packages/solid-router/tests/loaders.test.tsx
+++ b/packages/solid-router/tests/loaders.test.tsx
@@ -320,6 +320,33 @@ test('throw error from beforeLoad when navigating to route', async () => {
   expect(indexElement).toBeInTheDocument()
 })
 
+test('throw abortError from loader upon initial load with basepath', async () => {
+  window.history.replaceState(null, 'root', '/app')
+  const rootRoute = createRootRoute({})
+
+  const indexRoute = createRoute({
+    getParentRoute: () => rootRoute,
+    path: '/',
+    loader: async () => {
+      return Promise.reject(new DOMException('Aborted', 'AbortError'))
+    },
+    component: () => <div>Index route content</div>,
+    errorComponent: () => (
+      <div data-testid="index-error">indexErrorComponent</div>
+    ),
+  })
+
+  const routeTree = rootRoute.addChildren([indexRoute])
+  const router = createRouter({ routeTree, basepath: '/app' })
+
+  render(() => <RouterProvider router={router} />)
+
+  const indexElement = await screen.findByText('Index route content')
+  expect(indexElement).toBeInTheDocument()
+  expect(screen.queryByTestId('index-error')).not.toBeInTheDocument()
+  expect(window.location.pathname.startsWith('/app')).toBe(true)
+})
+
 test('reproducer #4245', async () => {
   const LOADER_WAIT_TIME = 500
   const rootRoute = createRootRoute({})

From 7d62f47ed1635acb85f99a63cf27167d154eaaee Mon Sep 17 00:00:00 2001
From: leesb971204 <leesb971204@gmail.com>
Date: Wed, 7 Jan 2026 09:40:09 +0900
Subject: [PATCH 2/2] fix(router-core): fix handle AbortError logic

Signed-off-by: leesb971204 <leesb971204@gmail.com>
---
 packages/router-core/src/load-matches.ts | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/packages/router-core/src/load-matches.ts b/packages/router-core/src/load-matches.ts
index 9d3a4b0aeb..87cb9ce34a 100644
--- a/packages/router-core/src/load-matches.ts
+++ b/packages/router-core/src/load-matches.ts
@@ -699,12 +699,11 @@ const runLoader = async (
     } catch (e) {
       let error = e
 
-      if (error instanceof DOMException && error.name === 'AbortError') {
-        const head = await executeHead(inner, matchId, route)
+      if ((error as any)?.name === 'AbortError') {
         inner.updateMatch(matchId, (prev) => ({
           ...prev,
           status: prev.status === 'pending' ? 'success' : prev.status,
-          ...head,
+          isFetching: false,
         }))
         return
       }
