kit-2.61-route-group-bug Svelte Themes

Kit 2.61 Route Group Bug

Minimal repro: SvelteKit 2.61.0 fails to match a +page.svelte nested in three route groups around a parametric ancestor (works on 2.60.1)

Repro: kit 2.61.0 fails to match +page.svelte nested in three route groups around a parametric ancestor

A leaf +page.svelte whose path nests inside three or more (group) segments — with a parametric ancestor — stops matching its bare URL on @sveltejs/[email protected]. The route still appears in the manifest and the param matcher is registered, but kit never selects it at runtime. event.route.id is null and the layout above the leaf does not run.

The observable response shape depends on whether a sibling route absorbs the URL:

Sibling under (meta)/ 2.60.1 2.61.0
[[anything]]/+page.server.ts /123 → leaf 200 ✅ /123 → sibling 302 (the sibling's redirect)
[anything]/+page.server.ts /123 → leaf 200 ✅ /123404
none /123 → leaf 200 ✅ /123404

In all three 2.61.0 cases the leaf (meta)/+page.svelte is the route that should match /123 — it just doesn't. The [[anything]] (optional) sibling is the only one that "absorbs" the orphaned URL (since [[ ]] matches with anything = undefined), turning a 404 into a silent 302 to wherever its load redirects. [anything] (required) cannot absorb the bare URL — it needs a segment — so the failure surfaces as a plain 404.

Same code on @sveltejs/[email protected] works correctly in every variant.

Suspected cause: PR #15861 ("avoid conflict for routes ending with optional parameters"), but the underlying problem is broader than that PR's scope — the leaf doesn't match even when no [[optional]] sibling exists.

Reproduction

pnpm install   # installs kit 2.61.0 (broken)
pnpm dev

Then:

curl -sI http://localhost:5173/123 | head -1
# kit 2.61.0:   HTTP/1.1 302 Found     (and Location: /)
# kit 2.60.1:   HTTP/1.1 200 OK

To check the 2.60.1 baseline against this same code:

pnpm add -D @sveltejs/[email protected]
rm -rf .svelte-kit
pnpm dev

Full demonstration matrix

Same route tree throughout. The only thing that varies between columns is whether a sibling exists under (meta)/ and whether the optional brackets are [[ ]] (optional) or [ ] (required).

URL 2.60.1 + [[anything]] 2.60.1 + [anything] 2.60.1 no sibling 2.61.0 + [[anything]] 2.61.0 + [anything] 2.61.0 no sibling
/123 200 200 200 302 → / 404 404
/123/news 200 ✅ 200 ✅ 200 ✅ 200 ✅ 200 ✅ 200 ✅
/123/junk 302 → /123 302 → /123 404 ✅ 302 → /123 302 → /123 404 ✅
/ 200 ✅ 200 ✅ 200 ✅ 200 ✅ 200 ✅ 200 ✅

Key observations:

  • All three 2.61.0 columns fail /123. The shape of the failure differs (302 vs 404) but the root cause is the same — (meta)/+page.svelte never matches /123.
  • [[anything]] (optional) vs [anything] (required) only affects what happens when the leaf is missing. [[ ]] claims the bare URL because the optional rest is allowed to be empty; [ ] cannot, because it requires a segment.
  • Sibling-specific routes (/news) are unaffected/123/news still matches news/+page.svelte in all six configurations. The breakage is isolated to the bare /{param} URL whose only possible match is the deeply nested leaf.

Bisected conditions (what is necessary to trigger)

  • Three or more route groups around the leaf. Removing the outer (series) group (so the path becomes [id]/(view)/(meta)/+page.svelte) makes /123 match correctly on 2.61.0. Two groups is not enough.
  • A parametric ancestor ([id]) above the groups.

Workarounds

  • Flatten one route-group level. Hoisting (meta)/+page.svelte to (view)/+page.svelte (so only two groups remain around the leaf) restores matching on 2.61.0. Requires moving sibling routes too if they shared (meta).
  • Pin to @sveltejs/[email protected] until an upstream patch lands.

Route tree

src/routes/
├── +layout.svelte
├── +page.svelte                                              # /
└── (series)/                                                 # <-- route group #1
    └── [id]/                                                 # parametric segment
        └── (view)/                                           # <-- route group #2
            ├── +layout.svelte
            ├── (meta)/                                       # <-- route group #3
            │   ├── +page.svelte                              # /{id}            ← BROKEN on 2.61.0
            │   └── [[anything]]/
            │       └── +page.server.ts                       # /{id}/{anything} ← absorbs /{id} on 2.61.0
            └── news/
                └── +page.svelte                              # /{id}/news       ← unaffected

Environment

  • @sveltejs/kit: 2.61.0 (broken) / 2.60.1 (working)
  • svelte: 5.55.9
  • vite: 7.3.3
  • @sveltejs/vite-plugin-svelte: 6.2.4
  • Node: 22+
  • OS: macOS 25.5 (also reproduces on Linux per production discovery)

Top categories

Loading Svelte Themes