diff --git a/.changeset/go-run-king.md b/.changeset/go-run-king.md
new file mode 100644
index 0000000000..a977a98e0a
--- /dev/null
+++ b/.changeset/go-run-king.md
@@ -0,0 +1,7 @@
+---
+'@tanstack/react-router': patch
+'@tanstack/solid-router': patch
+'@tanstack/vue-router': patch
+---
+
+Fix redirected pending route transitions so lazy target routes can finish loading without stale redirected matches causing render errors.
diff --git a/packages/react-router/src/Match.tsx b/packages/react-router/src/Match.tsx
index ae30f4b7ec..a8436d0ae5 100644
--- a/packages/react-router/src/Match.tsx
+++ b/packages/react-router/src/Match.tsx
@@ -259,6 +259,22 @@ export const MatchInner = React.memo(function MatchInnerImpl({
 }): any {
   const router = useRouter()
 
+  const getMatchPromise = (
+    match: {
+      id: string
+      _nonReactive: {
+        displayPendingPromise?: Promise<void>
+        minPendingPromise?: Promise<void>
+        loadPromise?: Promise<void>
+      }
+    },
+    key: 'displayPendingPromise' | 'minPendingPromise' | 'loadPromise',
+  ) => {
+    return (
+      router.getMatch(match.id)?._nonReactive[key] ?? match._nonReactive[key]
+    )
+  }
+
   if (isServer ?? router.isServer) {
     const match = router.stores.activeMatchStoresById.get(matchId)?.state
     if (!match) {
@@ -287,15 +303,15 @@ export const MatchInner = React.memo(function MatchInnerImpl({
     const out = Comp ? <Comp key={key} /> : <Outlet />
 
     if (match._displayPending) {
-      throw router.getMatch(match.id)?._nonReactive.displayPendingPromise
+      throw getMatchPromise(match, 'displayPendingPromise')
     }
 
     if (match._forcePending) {
-      throw router.getMatch(match.id)?._nonReactive.minPendingPromise
+      throw getMatchPromise(match, 'minPendingPromise')
     }
 
     if (match.status === 'pending') {
-      throw router.getMatch(match.id)?._nonReactive.loadPromise
+      throw getMatchPromise(match, 'loadPromise')
     }
 
     if (match.status === 'notFound') {
@@ -317,7 +333,7 @@ export const MatchInner = React.memo(function MatchInnerImpl({
 
         invariant()
       }
-      throw router.getMatch(match.id)?._nonReactive.loadPromise
+      throw getMatchPromise(match, 'loadPromise')
     }
 
     if (match.status === 'error') {
@@ -384,11 +400,11 @@ export const MatchInner = React.memo(function MatchInnerImpl({
   }, [key, route.options.component, router.options.defaultComponent])
 
   if (match._displayPending) {
-    throw router.getMatch(match.id)?._nonReactive.displayPendingPromise
+    throw getMatchPromise(match, 'displayPendingPromise')
   }
 
   if (match._forcePending) {
-    throw router.getMatch(match.id)?._nonReactive.minPendingPromise
+    throw getMatchPromise(match, 'minPendingPromise')
   }
 
   // see also hydrate() in packages/router-core/src/ssr/ssr-client.ts
@@ -413,7 +429,7 @@ export const MatchInner = React.memo(function MatchInnerImpl({
         }
       }
     }
-    throw router.getMatch(match.id)?._nonReactive.loadPromise
+    throw getMatchPromise(match, 'loadPromise')
   }
 
   if (match.status === 'notFound') {
@@ -428,8 +444,10 @@ export const MatchInner = React.memo(function MatchInnerImpl({
   }
 
   if (match.status === 'redirected') {
-    // Redirects should be handled by the router transition. If we happen to
-    // encounter a redirect here, it's a bug. Let's warn, but render nothing.
+    // A match can be observed as redirected during an in-flight transition,
+    // especially when pending UI is already rendering. Suspend on the match's
+    // load promise so React can abandon this stale render and continue the
+    // redirect transition.
     if (!isRedirect(match.error)) {
       if (process.env.NODE_ENV !== 'production') {
         throw new Error('Invariant failed: Expected a redirect error')
@@ -438,11 +456,7 @@ export const MatchInner = React.memo(function MatchInnerImpl({
       invariant()
     }
 
-    // warning(
-    //   false,
-    //   'Tried to render a redirected route match! This is a weird circumstance, please file an issue!',
-    // )
-    throw router.getMatch(match.id)?._nonReactive.loadPromise
+    throw getMatchPromise(match, 'loadPromise')
   }
 
   if (match.status === 'error') {
diff --git a/packages/react-router/tests/lazy/normal.tsx b/packages/react-router/tests/lazy/normal.tsx
index 1addf96c74..675deb83f3 100644
--- a/packages/react-router/tests/lazy/normal.tsx
+++ b/packages/react-router/tests/lazy/normal.tsx
@@ -2,7 +2,7 @@ import { createLazyFileRoute, createLazyRoute } from '../../src'
 
 export function Route(id: string) {
   return createLazyRoute(id)({
-    component: () => <h1>I'm a normal route</h1>,
+    component: () => <h1 data-testid="lazy-route-page">I'm a normal route</h1>,
   })
 }
 
diff --git a/packages/react-router/tests/redirect.test.tsx b/packages/react-router/tests/redirect.test.tsx
index a391d02898..cc15f0da36 100644
--- a/packages/react-router/tests/redirect.test.tsx
+++ b/packages/react-router/tests/redirect.test.tsx
@@ -1,3 +1,4 @@
+import * as React from 'react'
 import {
   cleanup,
   configure,
@@ -10,6 +11,7 @@ import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest'
 
 import {
   Link,
+  Outlet,
   RouterProvider,
   createBrowserHistory,
   createMemoryHistory,
@@ -111,6 +113,52 @@ describe('redirect', () => {
       expect(nestedFooLoaderMock).toHaveBeenCalled()
     })
 
+    test('when root `beforeLoad` redirects while root pendingComponent is showing and the target route is lazy', async () => {
+      let hasRedirected = false
+      const consoleError = vi
+        .spyOn(console, 'error')
+        .mockImplementation(() => {})
+
+      const rootRoute = createRootRoute({
+        component: () => <Outlet />,
+        pendingMs: 0,
+        pendingComponent: () => <div data-testid="pending">loading</div>,
+        beforeLoad: async () => {
+          await sleep(WAIT_TIME)
+          if (!hasRedirected) {
+            hasRedirected = true
+            throw redirect({ to: '/posts' })
+          }
+        },
+      })
+
+      const indexRoute = createRoute({
+        getParentRoute: () => rootRoute,
+        path: '/',
+        component: () => <div data-testid="index-page">Index page</div>,
+      })
+
+      const postsRoute = createRoute({
+        getParentRoute: () => rootRoute,
+        path: '/posts',
+      }).lazy(() => import('./lazy/normal').then((d) => d.Route('/posts')))
+
+      const router = createRouter({
+        routeTree: rootRoute.addChildren([indexRoute, postsRoute]),
+        history,
+      })
+
+      render(<RouterProvider router={router} />)
+
+      // The lazy target route adds the async boundary that exposes the stale
+      // redirected-match render path this regression is guarding.
+      expect(await screen.findByTestId('lazy-route-page')).toBeInTheDocument()
+      expect(screen.queryByTestId('pending')).not.toBeInTheDocument()
+      expect(router.state.location.href).toBe('/posts')
+      expect(router.state.status).toBe('idle')
+      expect(consoleError).not.toHaveBeenCalled()
+    })
+
     test('when `redirect` is thrown in `loader`', async () => {
       const nestedLoaderMock = vi.fn()
       const nestedFooLoaderMock = vi.fn()
diff --git a/packages/solid-router/src/Match.tsx b/packages/solid-router/src/Match.tsx
index b1f1c2b824..156c3847fb 100644
--- a/packages/solid-router/src/Match.tsx
+++ b/packages/solid-router/src/Match.tsx
@@ -273,6 +273,22 @@ export const MatchInner = (): any => {
           return <Outlet />
         }
 
+        const getLoadPromise = (
+          matchId: string,
+          fallbackMatch:
+            | {
+                _nonReactive: {
+                  loadPromise?: Promise<void>
+                }
+              }
+            | undefined,
+        ) => {
+          return (
+            router.getMatch(matchId)?._nonReactive.loadPromise ??
+            fallbackMatch?._nonReactive.loadPromise
+          )
+        }
+
         const keyedOut = () => (
           <Solid.Show when={componentKey()} keyed>
             {(_key) => out()}
@@ -375,6 +391,9 @@ export const MatchInner = (): any => {
             </Solid.Match>
             <Solid.Match when={currentMatch().status === 'redirected'}>
               {(_) => {
+                const matchId = currentMatch().id
+                const routerMatch = router.getMatch(matchId)
+
                 if (!isRedirect(currentMatch().error)) {
                   if (process.env.NODE_ENV !== 'production') {
                     throw new Error(
@@ -387,8 +406,7 @@ export const MatchInner = (): any => {
 
                 const [loaderResult] = Solid.createResource(async () => {
                   await new Promise((r) => setTimeout(r, 0))
-                  return router.getMatch(currentMatch().id)?._nonReactive
-                    .loadPromise
+                  return getLoadPromise(matchId, routerMatch)
                 })
 
                 return <>{loaderResult()}</>
diff --git a/packages/solid-router/tests/lazy/normal.tsx b/packages/solid-router/tests/lazy/normal.tsx
index 5b0f169da4..61eba8ab02 100644
--- a/packages/solid-router/tests/lazy/normal.tsx
+++ b/packages/solid-router/tests/lazy/normal.tsx
@@ -2,7 +2,7 @@ import { createLazyFileRoute, createLazyRoute } from '../../src'
 
 export function Route(id: string) {
   return createLazyRoute(id)({
-    component: () => <h1>I'm a normal route</h1>,
+    component: () => <h1 data-testid="lazy-route-page">I'm a normal route</h1>,
   })
 }
 
diff --git a/packages/solid-router/tests/redirect.test.tsx b/packages/solid-router/tests/redirect.test.tsx
index 5d3ecc898a..81bd1f6bc6 100644
--- a/packages/solid-router/tests/redirect.test.tsx
+++ b/packages/solid-router/tests/redirect.test.tsx
@@ -4,6 +4,7 @@ import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest'
 
 import {
   Link,
+  Outlet,
   RouterProvider,
   createBrowserHistory,
   createMemoryHistory,
@@ -104,6 +105,52 @@ describe('redirect', () => {
       expect(nestedFooLoaderMock).toHaveBeenCalled()
     })
 
+    test('when root `beforeLoad` redirects while root pendingComponent is showing and the target route is lazy', async () => {
+      let hasRedirected = false
+      const consoleError = vi
+        .spyOn(console, 'error')
+        .mockImplementation(() => {})
+
+      const rootRoute = createRootRoute({
+        component: () => <Outlet />,
+        pendingMs: 0,
+        pendingComponent: () => <div data-testid="pending">loading</div>,
+        beforeLoad: async () => {
+          await sleep(WAIT_TIME)
+          if (!hasRedirected) {
+            hasRedirected = true
+            throw redirect({ to: '/posts' })
+          }
+        },
+      })
+
+      const indexRoute = createRoute({
+        getParentRoute: () => rootRoute,
+        path: '/',
+        component: () => <div data-testid="index-page">Index page</div>,
+      })
+
+      const postsRoute = createRoute({
+        getParentRoute: () => rootRoute,
+        path: '/posts',
+      }).lazy(() => import('./lazy/normal').then((d) => d.Route('/posts')))
+
+      const router = createRouter({
+        routeTree: rootRoute.addChildren([indexRoute, postsRoute]),
+        history,
+      })
+
+      render(() => <RouterProvider router={router} />)
+
+      // The lazy target route adds the async boundary that exposes the stale
+      // redirected-match render path this regression is guarding.
+      expect(await screen.findByTestId('lazy-route-page')).toBeInTheDocument()
+      expect(screen.queryByTestId('pending')).not.toBeInTheDocument()
+      expect(router.state.location.href).toBe('/posts')
+      expect(router.state.status).toBe('idle')
+      expect(consoleError).not.toHaveBeenCalled()
+    })
+
     test('when `redirect` is thrown in `loader`', async () => {
       const nestedLoaderMock = vi.fn()
       const nestedFooLoaderMock = vi.fn()
diff --git a/packages/vue-router/src/Match.tsx b/packages/vue-router/src/Match.tsx
index f078986be7..70d50ced4d 100644
--- a/packages/vue-router/src/Match.tsx
+++ b/packages/vue-router/src/Match.tsx
@@ -337,6 +337,7 @@ export const MatchInner = Vue.defineComponent({
           ssr: match.ssr,
           _forcePending: match._forcePending,
           _displayPending: match._displayPending,
+          _nonReactive: match._nonReactive,
         },
         remountKey,
       }
@@ -350,6 +351,22 @@ export const MatchInner = Vue.defineComponent({
     const match = Vue.computed(() => combinedState.value?.match)
     const remountKey = Vue.computed(() => combinedState.value?.remountKey)
 
+    const getMatchPromise = (
+      match: {
+        id: string
+        _nonReactive: {
+          displayPendingPromise?: Promise<void>
+          minPendingPromise?: Promise<void>
+          loadPromise?: Promise<void>
+        }
+      },
+      key: 'displayPendingPromise' | 'minPendingPromise' | 'loadPromise',
+    ) => {
+      return (
+        router.getMatch(match.id)?._nonReactive[key] ?? match._nonReactive[key]
+      )
+    }
+
     return (): VNode | null => {
       // If match doesn't exist, return null (component is being unmounted or not ready)
       if (!combinedState.value || !match.value || !route.value) return null
@@ -390,7 +407,7 @@ export const MatchInner = Vue.defineComponent({
 
           invariant()
         }
-        throw router.getMatch(match.value.id)?._nonReactive.loadPromise
+        throw getMatchPromise(match.value, 'loadPromise')
       }
 
       if (match.value.status === 'error') {
diff --git a/packages/vue-router/tests/lazy/normal.tsx b/packages/vue-router/tests/lazy/normal.tsx
index 5b0f169da4..61eba8ab02 100644
--- a/packages/vue-router/tests/lazy/normal.tsx
+++ b/packages/vue-router/tests/lazy/normal.tsx
@@ -2,7 +2,7 @@ import { createLazyFileRoute, createLazyRoute } from '../../src'
 
 export function Route(id: string) {
   return createLazyRoute(id)({
-    component: () => <h1>I'm a normal route</h1>,
+    component: () => <h1 data-testid="lazy-route-page">I'm a normal route</h1>,
   })
 }
 
diff --git a/packages/vue-router/tests/redirect.test.tsx b/packages/vue-router/tests/redirect.test.tsx
index f198f8adf6..b7ba2e1af3 100644
--- a/packages/vue-router/tests/redirect.test.tsx
+++ b/packages/vue-router/tests/redirect.test.tsx
@@ -4,6 +4,7 @@ import { afterEach, describe, expect, test, vi } from 'vitest'
 
 import {
   Link,
+  Outlet,
   RouterProvider,
   createMemoryHistory,
   createRootRoute,
@@ -94,6 +95,51 @@ describe('redirect', () => {
       expect(nestedFooLoaderMock).toHaveBeenCalled()
     })
 
+    test('when root `beforeLoad` redirects while root pendingComponent is showing and the target route is lazy', async () => {
+      let hasRedirected = false
+      const consoleError = vi
+        .spyOn(console, 'error')
+        .mockImplementation(() => {})
+
+      const rootRoute = createRootRoute({
+        component: () => <Outlet />,
+        pendingMs: 0,
+        pendingComponent: () => <div data-testid="pending">loading</div>,
+        beforeLoad: async () => {
+          await sleep(WAIT_TIME)
+          if (!hasRedirected) {
+            hasRedirected = true
+            throw redirect({ to: '/posts' })
+          }
+        },
+      })
+
+      const indexRoute = createRoute({
+        getParentRoute: () => rootRoute,
+        path: '/',
+        component: () => <div data-testid="index-page">Index page</div>,
+      })
+
+      const postsRoute = createRoute({
+        getParentRoute: () => rootRoute,
+        path: '/posts',
+      }).lazy(() => import('./lazy/normal').then((d) => d.Route('/posts')))
+
+      const router = createRouter({
+        routeTree: rootRoute.addChildren([indexRoute, postsRoute]),
+        history: createMemoryHistory({ initialEntries: ['/'] }),
+      })
+
+      render(<RouterProvider router={router} />)
+
+      // The lazy target route adds the async boundary that exposes the stale
+      // redirected-match render path this regression is guarding.
+      expect(await screen.findByTestId('lazy-route-page')).toBeInTheDocument()
+      expect(screen.queryByTestId('pending')).not.toBeInTheDocument()
+      expect(router.state.location.href).toBe('/posts')
+      expect(consoleError).not.toHaveBeenCalled()
+    })
+
     test('when `redirect` is thrown in `loader`', async () => {
       const nestedLoaderMock = vi.fn()
       const nestedFooLoaderMock = vi.fn()
