nextjs - ✅(Solved) Fix Turbopack build fails when optional catch-all layout exports generateStaticParams alongside parallel routes [1 pull requests, 3 comments, 4 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
vercel/next.js#84509Fetched 2026-04-08 02:19:05
View on GitHub
Comments
3
Participants
4
Timeline
15
Reactions
1
Assignees
Timeline (top)
labeled ×4commented ×3assigned ×1closed ×1

Error Message

TypeError: Cannot destructure property 'repeat' of 'regex.groups[paramName]' as it is undefined. at ignore-listed frames

Build error occurred Error: Failed to collect page data for /[tenant]/c

Fix Action

Fix / Workaround

Using this patch as a workaround:

diff --git a/dist/build/static-paths/app.js b/dist/build/static-paths/app.js
index 1a6b37fa742cc8c47c4b9ae0021d34537bf6c569..de26ca61af03caf08ab5754cda93b8186fc59e62 100644
--- a/dist/build/static-paths/app.js
+++ b/dist/build/static-paths/app.js
@@ -567,6 +567,9 @@ async function buildAppStaticPaths({ dir, page, distDir, cacheComponents, authIn
         } else {
             // Collect all the route param keys that are not parallel route params.
             // These are the ones that will be included in the request pathname.
+            if (!(regex.groups && regex.groups[segment.paramName])) {
+                continue;
+            }
             childrenRouteParamSegments.push({
                 name: segment.name,
                 paramName: segment.paramName,
@@ -637,7 +640,9 @@ async function buildAppStaticPaths({ dir, page, distDir, cacheComponents, authIn
     // Precompile the regex patterns for the route params.
     const paramPatterns = new Map();
     for (const { paramName } of childrenRouteParamSegments){
-        const { repeat, optional } = regex.groups[paramName];
+        const group = regex.groups[paramName];
+        if (!group) continue;
+        const { repeat, optional } = group;
         let pattern = `[${repeat ? '...' : ''}${paramName}]`;
         if (optional) {
             pattern = `[${pattern}]`;

PR fix notes

PR #85074: Fix build crash with parallel routes and root-level dynamic parameters

Description (problem / solution / changelog)

What?

Fixes a build-time crash that occurs when using parallel routes (@slot syntax) combined with root-level dynamic parameters (e.g., [locale]) in the App Router.

Why?

When building static paths for routes with both parallel routes and root-level dynamic parameters, the build would crash during pathname generation. This happened because the code was using RouteRegex.groups to determine parameter properties (repeat/optional), but the regex groups didn't properly handle segment names for nested parallel route structures. The pathname replacement logic would fail when trying to match segment patterns, causing the build to abort.

This is a critical issue because it blocks developers from using a common pattern: internationalization with parallel routes (e.g., /[locale]/@modal/...).

How?

The fix refactors the parameter validation logic to use DynamicParamTypes directly instead of relying on RouteRegex:

  1. Created a new getParamProperties() utility in get-segment-param.tsx that determines repeat and optional properties based on the parameter type (catchall, optional-catchall, dynamic, etc.)
  2. Updated buildAppStaticPaths() to use this utility instead of RouteRegex.groups
  3. Changed pathname replacement to use the segment name from childrenRouteParamSegments rather than reconstructing it from the regex pattern

This approach:

  • Eliminates the mismatch between regex-based pattern matching and actual segment structure
  • Properly handles parallel route segment names
  • Makes the code more maintainable by using the type system instead of regex internals

Fixes #84509

Changed files

  • packages/next/errors.json (modified, +2/-1)
  • packages/next/src/build/static-paths/app.ts (modified, +17/-27)
  • packages/next/src/shared/lib/router/utils/get-segment-param.tsx (modified, +26/-0)
  • test/e2e/app-dir/parallel-routes-catchall-slotted-non-catchalls/app/[locale]/@slot/default.tsx (added, +3/-0)
  • test/e2e/app-dir/parallel-routes-catchall-slotted-non-catchalls/app/[locale]/@slot/other/page.tsx (added, +3/-0)
  • test/e2e/app-dir/parallel-routes-catchall-slotted-non-catchalls/app/[locale]/layout.tsx (added, +14/-0)
  • test/e2e/app-dir/parallel-routes-catchall-slotted-non-catchalls/app/layout.tsx (modified, +1/-3)

Code Example

npx degit luishdz1010/next-bug-turbo-parallel-routes next-bug-turbo-parallel-routes
cd next-bug-turbo-parallel-routes
pnpm install

---

TypeError: Cannot destructure property 'repeat' of 'regex.groups[paramName]' as it is undefined.
    at ignore-listed frames

> Build error occurred
Error: Failed to collect page data for /[tenant]/c

---

Operating System:
  Platform: linux
  Arch: x64
  Version: #202508231538~1757385336~22.04~8f363f2 SMP PREEMPT_DYNAMIC Tue S
  Available memory (MB): 94177
  Available CPU cores: 32
Binaries:
  Node: 24.9.0
  npm: 11.6.0
  Yarn: N/A
  pnpm: 9.15.4
Relevant Packages:
  next: 15.6.0-canary.42 // Latest available version is detected (15.6.0-canary.42).
  eslint-config-next: N/A
  react: 19.2.0
  react-dom: 19.2.0
  typescript: 5.9.3
Next.js Config:
  output: N/A

---

diff --git a/dist/build/static-paths/app.js b/dist/build/static-paths/app.js
index 1a6b37fa742cc8c47c4b9ae0021d34537bf6c569..de26ca61af03caf08ab5754cda93b8186fc59e62 100644
--- a/dist/build/static-paths/app.js
+++ b/dist/build/static-paths/app.js
@@ -567,6 +567,9 @@ async function buildAppStaticPaths({ dir, page, distDir, cacheComponents, authIn
         } else {
             // Collect all the route param keys that are not parallel route params.
             // These are the ones that will be included in the request pathname.
+            if (!(regex.groups && regex.groups[segment.paramName])) {
+                continue;
+            }
             childrenRouteParamSegments.push({
                 name: segment.name,
                 paramName: segment.paramName,
@@ -637,7 +640,9 @@ async function buildAppStaticPaths({ dir, page, distDir, cacheComponents, authIn
     // Precompile the regex patterns for the route params.
     const paramPatterns = new Map();
     for (const { paramName } of childrenRouteParamSegments){
-        const { repeat, optional } = regex.groups[paramName];
+        const group = regex.groups[paramName];
+        if (!group) continue;
+        const { repeat, optional } = group;
         let pattern = `[${repeat ? '...' : ''}${paramName}]`;
         if (optional) {
             pattern = `[${pattern}]`;
RAW_BUFFERClick to expand / collapse

Link to the code that reproduces this issue

https://github.com/luishdz1010/next-bug-turbo-parallel-routes

To Reproduce

  1. Clone this reproduction repo:
npx degit luishdz1010/next-bug-turbo-parallel-routes next-bug-turbo-parallel-routes
cd next-bug-turbo-parallel-routes
pnpm install
  1. Run pnpm build.

  2. Observe the failure while collecting page data for /[tenant]/c with the referenced stack trace.

Current vs. Expected behavior

next build fails under Turbopack when a layout for app/[tenant]/[[...pages]] exports generateStaticParams while the same route tree also defines a parallel route slot (@nav/c). During static path generation Turbopack attempts to destructure the param descriptor for pages from the regex associated with /[tenant]/c, but that route does not declare the optional catch-all param, leading to:

TypeError: Cannot destructure property 'repeat' of 'regex.groups[paramName]' as it is undefined.
    at ignore-listed frames

> Build error occurred
Error: Failed to collect page data for /[tenant]/c

Works fine with --webpack, also works fine with Turbo's dev mode.

Expected

next build should succeed with Turbopack. Routes that do not define a pages param should not receive static params generated for sibling branches.

Provide environment information

Operating System:
  Platform: linux
  Arch: x64
  Version: #202508231538~1757385336~22.04~8f363f2 SMP PREEMPT_DYNAMIC Tue S
  Available memory (MB): 94177
  Available CPU cores: 32
Binaries:
  Node: 24.9.0
  npm: 11.6.0
  Yarn: N/A
  pnpm: 9.15.4
Relevant Packages:
  next: 15.6.0-canary.42 // Latest available version is detected (15.6.0-canary.42).
  eslint-config-next: N/A
  react: 19.2.0
  react-dom: 19.2.0
  typescript: 5.9.3
Next.js Config:
  output: N/A

Which area(s) are affected? (Select all that apply)

Turbopack, Parallel & Intercepting Routes

Which stage(s) are affected? (Select all that apply)

next build (local)

Additional context

Using this patch as a workaround:

diff --git a/dist/build/static-paths/app.js b/dist/build/static-paths/app.js
index 1a6b37fa742cc8c47c4b9ae0021d34537bf6c569..de26ca61af03caf08ab5754cda93b8186fc59e62 100644
--- a/dist/build/static-paths/app.js
+++ b/dist/build/static-paths/app.js
@@ -567,6 +567,9 @@ async function buildAppStaticPaths({ dir, page, distDir, cacheComponents, authIn
         } else {
             // Collect all the route param keys that are not parallel route params.
             // These are the ones that will be included in the request pathname.
+            if (!(regex.groups && regex.groups[segment.paramName])) {
+                continue;
+            }
             childrenRouteParamSegments.push({
                 name: segment.name,
                 paramName: segment.paramName,
@@ -637,7 +640,9 @@ async function buildAppStaticPaths({ dir, page, distDir, cacheComponents, authIn
     // Precompile the regex patterns for the route params.
     const paramPatterns = new Map();
     for (const { paramName } of childrenRouteParamSegments){
-        const { repeat, optional } = regex.groups[paramName];
+        const group = regex.groups[paramName];
+        if (!group) continue;
+        const { repeat, optional } = group;
         let pattern = `[${repeat ? '...' : ''}${paramName}]`;
         if (optional) {
             pattern = `[${pattern}]`;

<sub>NEXT-4747</sub>

extent analysis

TL;DR

Apply the provided patch to the buildAppStaticPaths function to fix the Turbopack build failure when using optional catch-all layouts.

Guidance

  • The issue arises from Turbopack attempting to destructure the param descriptor for pages from the regex associated with /[tenant]/c, which does not declare the optional catch-all param.
  • The provided patch adds a check to ensure that regex.groups[paramName] exists before attempting to destructure it, preventing the TypeError.
  • To apply the patch, update the buildAppStaticPaths function in dist/build/static-paths/app.js with the provided changes.
  • Verify that the patch fixes the issue by running pnpm build again and checking for any errors.

Example

The patch provided in the issue body can be applied directly to the buildAppStaticPaths function:

diff --git a/dist/build/static-paths/app.js b/dist/build/static-paths/app.js
index 1a6b37fa742cc8c47c4b9ae0021d34537bf6c569..de26ca61af03caf08ab5754cda93b8186fc59e62 100644
--- a/dist/build/static-paths/app.js
+++ b/dist/build/static-paths/app.js
@@ -567,6 +567,9 @@ async function buildAppStaticPaths({ dir, page, distDir, cacheComponents, authIn
         } else {
             // Collect all the route param keys that are not parallel route params.
             // These are the ones that will be included in the request pathname.
+            if (!(regex.groups && regex.groups[segment.paramName])) {
+                continue;
+            }
             childrenRouteParamSegments.push({
                 name: segment.name,
                 paramName: segment.paramName,
@@ -637,7 +640,9 @@ async function buildAppStaticPaths({ dir, page, distDir, cacheComponents, authIn
     // Precompile the regex patterns for the route params.
     const paramPatterns = new Map();
     for (const { paramName } of childrenRouteParamSegments){
-        const { repeat, optional } = regex.groups[paramName];
+        const group = regex.groups[paramName];
+        if (!group) continue;
+        const { repeat, optional } = group;
         let pattern = `[${repeat ? '...' : ''}${paramName}]`;
         if (optional) {
             pattern = `[${pattern}]`;

Notes

The provided patch is a workaround for the issue, and it may not be the final solution. The root cause of the issue is likely related to how Turbopack handles optional catch-all layouts, and a more permanent fix may require changes to the Next.js or Turbopack codebase.

Recommendation

Apply the provided patch to the `buildAppStatic

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING