From db335c23d85d486d7ae150a676a814bd7346d6e9 Mon Sep 17 00:00:00 2001 From: Sheraff Date: Wed, 21 Jan 2026 16:37:15 +0100 Subject: [PATCH] fix(router-core): skipOnParamError on index route should still allow mathing other node types beyond it on error --- .../router-core/src/new-process-route-tree.ts | 21 +++++++----- .../tests/skip-route-on-parse-error.test.ts | 33 +++++++++++++++++++ 2 files changed, 45 insertions(+), 9 deletions(-) diff --git a/packages/router-core/src/new-process-route-tree.ts b/packages/router-core/src/new-process-route-tree.ts index 2dcaceebd35..bbe3b930418 100644 --- a/packages/router-core/src/new-process-route-tree.ts +++ b/packages/router-core/src/new-process-route-tree.ts @@ -1067,18 +1067,21 @@ function getNodeMatch( rawParams, parsedParams, } + let indexValid = true if (node.index.skipOnParamError) { const result = validateMatchParams(path, parts, indexFrame) - if (!result) continue + if (!result) indexValid = false } - // perfect match, no need to continue - // this is an optimization, algorithm should work correctly without this block - if (statics === partsLength && !dynamics && !optionals && !skipped) { - return indexFrame - } - if (isFrameMoreSpecific(bestMatch, indexFrame)) { - // index matches skip the stack because they cannot have children - bestMatch = indexFrame + if (indexValid) { + // perfect match, no need to continue + // this is an optimization, algorithm should work correctly without this block + if (statics === partsLength && !dynamics && !optionals && !skipped) { + return indexFrame + } + if (isFrameMoreSpecific(bestMatch, indexFrame)) { + // index matches skip the stack because they cannot have children + bestMatch = indexFrame + } } } diff --git a/packages/router-core/tests/skip-route-on-parse-error.test.ts b/packages/router-core/tests/skip-route-on-parse-error.test.ts index 9c40af7c996..433ecc6b9a7 100644 --- a/packages/router-core/tests/skip-route-on-parse-error.test.ts +++ b/packages/router-core/tests/skip-route-on-parse-error.test.ts @@ -636,6 +636,39 @@ describe('skipRouteOnParseError', () => { expect(otherResult?.route.id).toBe('/files') expect(otherResult?.rawParams['**']).toBe('../../secret/photo.jpg') }) + it('index parse failure does not block wildcard sibling', () => { + const tree = { + id: '__root__', + isRoot: true, + fullPath: '/', + path: '/', + children: [ + { + id: '/a/', + fullPath: '/a/', + path: 'a/', + options: { + params: { + parse: () => { + throw new Error('Invalid index') + }, + }, + skipRouteOnParseError: { params: true }, + }, + }, + { + id: '/a/$', + fullPath: '/a/$', + path: 'a/$', + options: {}, + }, + ], + } + const { processedTree } = processRouteTree(tree) + const result = findRouteMatch('/a', processedTree) + expect(result?.route.id).toBe('/a/$') + expect(result?.rawParams).toEqual({ '*': '', _splat: '' }) + }) }) describe('multiple validated routes competing', () => {