[PR #348] [MERGED] fix: layout not receiving correct params #497

Closed
opened 2026-05-06 13:08:23 +02:00 by BreizhHardware · 0 comments

📋 Pull Request Information

Original PR: https://github.com/cloudflare/vinext/pull/348
Author: @james-elicx
Created: 3/8/2026
Status: Merged
Merged: 3/8/2026
Merged by: @james-elicx

Base: mainHead: j-branch-4


📝 Commits (2)

  • 6cd7099 fix: layout not receiving correct params
  • 607f979 fix: layout not getting correct params on 404

📊 Changes

10 files changed (+225 additions, -13 deletions)

View changed files

📝 packages/vinext/src/server/app-dev-server.ts (+18 -12)
tests/e2e/app-router/layout-params.spec.ts (+119 -0)
📝 tests/e2e/app-router/ssr.spec.ts (+1 -1)
tests/fixtures/app-basic/app/blog/[slug]/layout.tsx (+31 -0)
tests/fixtures/app-basic/app/nextjs-compat/layout-params-notfound/[slug]/layout.tsx (+15 -0)
tests/fixtures/app-basic/app/nextjs-compat/layout-params-notfound/[slug]/not-found.tsx (+13 -0)
tests/fixtures/app-basic/app/nextjs-compat/layout-params-notfound/[slug]/page.tsx (+19 -0)
tests/fixtures/app-basic/app/nextjs-compat/layout-params-notfound/layout.tsx (+3 -0)
tests/fixtures/app-basic/app/nextjs-compat/layout-params-notfound/not-found.tsx (+3 -0)
tests/fixtures/app-basic/app/nextjs-compat/layout-params-notfound/page.tsx (+3 -0)

📄 Description

fixes #346

fix: pass matched params to layouts in renderHTTPAccessFallbackPage**

When notFound(), forbidden(), or unauthorized() is thrown from a page component, renderHTTPAccessFallbackPage re-renders the layout tree wrapping the fallback boundary. The layouts receive a params prop — but the function was reading opts?.params which was never set at any call site (the callers all passed { params } before the rename, which put the value on the wrong key). The fallback fell through to route?.params ?? {} which is the static array of param names from the route scan, not the matched values. So every layout in the fallback tree received {}, causing await params to resolve to {} and any destructuring of param keys (e.g. const { slug } = await params) to silently produce undefined — or crash with Cannot destructure property 'slug' of '(intermediate value)' as it is undefined in the SSR pass.

The fix renames the option key from params to matchedParams throughout and reads it correctly in renderHTTPAccessFallbackPage. A second duplicate call block that was added in the layout pre-render loop (dead code after the if that already returns) is also removed.

Regression test: layout-params-notfound/[slug]/layout.tsx always renders and sets data-slug from await params. The page calls notFound() for invalid slugs, forcing renderHTTPAccessFallbackPage to re-render the layout. The test asserts data-slug="bad-slug" on the wrapper — this is only true if the real matched params were forwarded. Without the fix the attribute is empty/undefined and the SSR pass crashes.


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/cloudflare/vinext/pull/348 **Author:** [@james-elicx](https://github.com/james-elicx) **Created:** 3/8/2026 **Status:** ✅ Merged **Merged:** 3/8/2026 **Merged by:** [@james-elicx](https://github.com/james-elicx) **Base:** `main` ← **Head:** `j-branch-4` --- ### 📝 Commits (2) - [`6cd7099`](https://github.com/cloudflare/vinext/commit/6cd709937dc45c9f7fa4644d828c942d5e61ab5e) fix: layout not receiving correct params - [`607f979`](https://github.com/cloudflare/vinext/commit/607f97953e58fb9b5c1863cb834d9590206682e2) fix: layout not getting correct params on 404 ### 📊 Changes **10 files changed** (+225 additions, -13 deletions) <details> <summary>View changed files</summary> 📝 `packages/vinext/src/server/app-dev-server.ts` (+18 -12) ➕ `tests/e2e/app-router/layout-params.spec.ts` (+119 -0) 📝 `tests/e2e/app-router/ssr.spec.ts` (+1 -1) ➕ `tests/fixtures/app-basic/app/blog/[slug]/layout.tsx` (+31 -0) ➕ `tests/fixtures/app-basic/app/nextjs-compat/layout-params-notfound/[slug]/layout.tsx` (+15 -0) ➕ `tests/fixtures/app-basic/app/nextjs-compat/layout-params-notfound/[slug]/not-found.tsx` (+13 -0) ➕ `tests/fixtures/app-basic/app/nextjs-compat/layout-params-notfound/[slug]/page.tsx` (+19 -0) ➕ `tests/fixtures/app-basic/app/nextjs-compat/layout-params-notfound/layout.tsx` (+3 -0) ➕ `tests/fixtures/app-basic/app/nextjs-compat/layout-params-notfound/not-found.tsx` (+3 -0) ➕ `tests/fixtures/app-basic/app/nextjs-compat/layout-params-notfound/page.tsx` (+3 -0) </details> ### 📄 Description fixes #346 fix: pass matched params to layouts in `renderHTTPAccessFallbackPage`** When `notFound()`, `forbidden()`, or `unauthorized()` is thrown from a page component, `renderHTTPAccessFallbackPage` re-renders the layout tree wrapping the fallback boundary. The layouts receive a `params` prop — but the function was reading `opts?.params` which was never set at any call site (the callers all passed `{ params }` before the rename, which put the value on the wrong key). The fallback fell through to `route?.params ?? {}` which is the static array of param *names* from the route scan, not the matched values. So every layout in the fallback tree received `{}`, causing `await params` to resolve to `{}` and any destructuring of param keys (e.g. `const { slug } = await params`) to silently produce `undefined` — or crash with `Cannot destructure property 'slug' of '(intermediate value)' as it is undefined` in the SSR pass. The fix renames the option key from `params` to `matchedParams` throughout and reads it correctly in `renderHTTPAccessFallbackPage`. A second duplicate call block that was added in the layout pre-render loop (dead code after the `if` that already returns) is also removed. **Regression test:** `layout-params-notfound/[slug]/layout.tsx` always renders and sets `data-slug` from `await params`. The page calls `notFound()` for invalid slugs, forcing `renderHTTPAccessFallbackPage` to re-render the layout. The test asserts `data-slug="bad-slug"` on the wrapper — this is only true if the real matched params were forwarded. Without the fix the attribute is empty/undefined and the SSR pass crashes. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
BreizhHardware 2026-05-06 13:08:23 +02:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/vinext#497
No description provided.