Repository: TanStack/router (2025-07-22T16:51:52Z)

Issue:
Navigating on the Client from optional Param with static Suffix to required Param Index matches wrong Parent
### Which project does this relate to?

Router

### Describe the bug

When navigating on the client from route with an optional param with a static suffix to the required param index the wrong parent is matched. This does not happen on intial request/ssr.

### Your Example Website or App

https://stackblitz.com/edit/tanstack-router-2z7ugykm?file=src%2Froutes%2Fadmin-levels%2F%7B-%24adminLevelId%7D%2Freports.tsx

### Steps to Reproduce the Bug or Issue

1. Click "Make first client-side navigation"
2. Click "Navigate to broken path"
3. Notice the broken structure in the devtools as well as the wrongly applied routes/layouts


```
/
/admin-levels
/admin-levels/{-$adminLevelId}
/admin-levels/$adminLevelId/
```

<img width="422" height="325" alt="Image" src="https://github.com/user-attachments/assets/acfbae39-e9ae-4684-8076-50e2b2e17a7e" />

### Expected behavior

The layout of the required param should be used.

### Screenshots or Videos

_No response_

### Platform

- Router / Start Version: 1.129.2


### Additional context

_No response_


Discussion:

Patch:
diff --git a/packages/router-core/src/path.ts b/packages/router-core/src/path.ts
index 18eed419457..58d54332262 100644
--- a/packages/router-core/src/path.ts
+++ b/packages/router-core/src/path.ts
@@ -454,6 +454,9 @@ export function interpolatePath({
           const value = encodeParam(segment.value)
           return `${segmentPrefix}${segment.value}${value ?? ''}${segmentSuffix}`
         }
+        if (leaveWildcards) {
+          return `${segmentPrefix}${key}${encodeParam(key) ?? ''}${segmentSuffix}`
+        }
         return `${segmentPrefix}${encodeParam(key) ?? ''}${segmentSuffix}`
       }
 


Test patch:
diff --git a/packages/react-router/tests/optional-path-params.test.tsx b/packages/react-router/tests/optional-path-params.test.tsx
index da632651463..670a845a8d0 100644
--- a/packages/react-router/tests/optional-path-params.test.tsx
+++ b/packages/react-router/tests/optional-path-params.test.tsx
@@ -225,6 +225,157 @@ describe('React Router - Optional Path Parameters', () => {
     )
   })
 
+  describe('required and optional parameters on the same level', () => {
+    async function setupTestRouter() {
+      const rootRoute = createRootRoute()
+
+      const indexRoute = createRoute({
+        getParentRoute: () => rootRoute,
+        path: '/',
+        component: () => {
+          return (
+            <div data-testid="index-route-component">
+              <h1>index</h1>
+              <Link
+                data-testid="reports-optional-param-link"
+                params={{ adminLevelId: 'asdf' }}
+                to="/admin-levels/{-$adminLevelId}/reports"
+              >
+                navigate to reports with optional param
+              </Link>
+            </div>
+          )
+        },
+      })
+
+      const adminLevelsRoutes = createRoute({
+        getParentRoute: () => rootRoute,
+
+        path: 'admin-levels',
+        component: () => (
+          <div data-testid="admin-levels-route-component">
+            <h1>admin-levels</h1>
+            <Outlet />
+          </div>
+        ),
+      })
+
+      const requiredParamRoute = createRoute({
+        getParentRoute: () => adminLevelsRoutes,
+        path: '$adminLevelId',
+        component: () => (
+          <div data-testid="admin-levels-route-required-param-route-component">
+            <h1>Required Param Route</h1>
+            <Outlet />
+          </div>
+        ),
+      })
+
+      const requiredParamIndexRoute = createRoute({
+        getParentRoute: () => requiredParamRoute,
+        path: '/',
+        component: () => (
+          <div data-testid="admin-levels-route-required-param-index-route-component">
+            <h1>Required Param Route Index</h1>
+          </div>
+        ),
+      })
+
+      const optionalParamRoute = createRoute({
+        getParentRoute: () => adminLevelsRoutes,
+        path: '{-$adminLevelId}',
+        component: () => (
+          <div data-testid="admin-levels-route-optional-param-route-component">
+            <h1>Optional Param Route</h1>
+            <Outlet />
+          </div>
+        ),
+      })
+
+      const reportsRoute = createRoute({
+        getParentRoute: () => optionalParamRoute,
+        path: 'reports',
+        component: () => (
+          <div data-testid="reports-route-component">
+            <h1>Reports</h1>
+            <Link
+              data-testid="navigate-to-required-param-link"
+              to="/admin-levels/$adminLevelId"
+              params={{ adminLevelId: 'asdf' }}
+            >
+              navigate to required param route
+            </Link>
+            <Outlet />
+          </div>
+        ),
+      })
+
+      const router = createRouter({
+        routeTree: rootRoute.addChildren([
+          indexRoute,
+          adminLevelsRoutes.addChildren([
+            requiredParamRoute.addChildren([requiredParamIndexRoute]),
+            optionalParamRoute.addChildren([reportsRoute]),
+          ]),
+        ]),
+      })
+
+      render(<RouterProvider router={router} />)
+      await act(() => router.load())
+      return router
+    }
+
+    it('direct visit', async () => {
+      window.history.replaceState({}, '', 'admin-levels/asdf')
+      await setupTestRouter()
+
+      expect(
+        await screen.findByTestId(
+          'admin-levels-route-required-param-route-component',
+        ),
+      ).toBeInTheDocument()
+      expect(
+        await screen.findByTestId(
+          'admin-levels-route-required-param-index-route-component',
+        ),
+      ).toBeInTheDocument()
+    })
+
+    it('client-side navigation', async () => {
+      window.history.replaceState({}, '', '/')
+
+      await setupTestRouter()
+
+      expect(
+        await screen.findByTestId('index-route-component'),
+      ).toBeInTheDocument()
+      const reportsLink = await screen.findByTestId(
+        'reports-optional-param-link',
+      )
+      fireEvent.click(reportsLink)
+
+      expect(
+        await screen.findByTestId('reports-route-component'),
+      ).toBeInTheDocument()
+      const requiredParamLink = await screen.findByTestId(
+        'navigate-to-required-param-link',
+      )
+      fireEvent.click(requiredParamLink)
+
+      expect(
+        await screen.findByTestId(
+          'admin-levels-route-required-param-route-component',
+        ),
+      ).toBeInTheDocument()
+
+      expect(
+        await screen.findByTestId(
+          'admin-levels-route-required-param-index-route-component',
+        ),
+      ).toBeInTheDocument()
+    })
+  })
+
   describe('Link component with optional parameters', () => {
     it('should generate correct href for optional parameters', async () => {
       const rootRoute = createRootRoute()