Repository navigation
Turbopack: report routes nested inside catch-all segments instead of panicking in dev - #101697
Merged
lukesandberg merged 2 commits intoNov 13, 2026
Merged
Conversation
…n Turbopack dev Co-authored-by: Luke Sandberg <210140+lukesandberg@users.noreply.github.com>
Contributor
|
Vercel Agent finished reviewing your changes and approved this pull request. Review steps (54.7s)Preparing the workspace 12.8s |
Contributor
Tests PassedCommit: ac3a666 |
lukesandberg
commented
Nov 12, 2026
lukesandberg
commented
Nov 12, 2026
lukesandberg
commented
Nov 12, 2026
lukesandberg
commented
Nov 12, 2026
…t issue text Co-authored-by: Luke Sandberg <210140+lukesandberg@users.noreply.github.com>
lukesandberg
marked this pull request as ready for review
November 13, 2026 02:25
lukesandberg
deleted the
fleet/turbopack-catch-all-illegal-route-issue
branch
November 13, 2026 02:25
jamiboym
added a commit
that referenced
this pull request
Nov 13, 2026
Resolve a conflict with #101697, which reports routes nested inside catch-all segments instead of panicking in Turbopack dev. Keep canary's isNestedInCatchAllSegment filter and this branch's exported verifyTypeScript. On this branch the filter's Turbopack case is unused, because Turbopack dev takes its routes from native discovery, which already skips those routes and reports the issue. #101697 also changed AppPage::clone_push_str to return its own error type and added a DirectoryTree destructuring in app_structure.rs. Adapt this branch's authored-file inventory to both: metadata nested inside a catch-all segment stays in the inventory without a runtime URL, and the new destructuring ignores the inventory fields.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A metadata file (
opengraph-image,twitter-image,icon, …) or any other route placed inside a catch-all segment, e.g.app/blog/[[...slug]]/opengraph-image.tsxorapp/blog/[...slug]/extra/page.tsx, crashednext devwith Turbopack:This placement is intentionally unsupported. A catch-all swallows every remaining segment, so such a route can never be matched (see #49630, #77061, #66355), and
next buildalready rejects it with a readable error. The problem was the whole dev process aborting with an internal error.Now Turbopack dev reports a regular app-structure error, the same way other invalid app structures are reported (e.g. conflicting route handlers):
The dev server stays up. Requests show the error until the file is moved, and then the app recovers without a restart.
How
crates/next-core/src/app_structure.rs: when a metadata route or a subdirectory would add a segment after a catch-all, emit a new Error-severityNestedInCatchAllSegmentIssue(paths, routes and segments rendered asCode) and skip that route instead of propagating theErr. A directory is only reported, once at its topmost invalid level, when its subtree actually contains a page, route handler or metadata file, so plain component folders inside a catch-all stay fine. The loader-tree builder skips those directories too.crates/next-core/src/next_app/mod.rs:AppPage::push(andpush_str/clone_push*) now return a structuredAppPageError, so callers can matchSegmentAfterCatchAll { catch_all, .. }instead of re-checking. The invariant and its messages are unchanged.packages/next/src/server/lib/router-utils/setup-dev-bundler.ts: with the Rust fix alone, dev still exited when such files already exist at startup. The initialgetSortedRoutesthrowsCatch-all must be the last part of the URL.and rejects dev setup. Later rescans only log a warning. For Turbopack only, routes nested inside a catch-all are now left out of that list, since Turbopack reports them itself and creates no entrypoints for them.Unchanged:
next build(still fails viavalidateAppPaths) and webpack dev (still exits with its existing readable error).Docs
docs/01-app/03-api-reference/03-file-conventions/01-metadata/opengraph-image.mdx: new troubleshooting section, "Using an image in a catch-all segment", with the Route Handler +generateMetadataworkaround.docs/01-app/03-api-reference/03-file-conventions/01-metadata/app-icons.mdx: the same note foricon/apple-icon.I searched the other docs, error pages, tests and comments and found nothing else that states or depends on this behavior.
Finding: https://next-maintainer-agent.vercel.tools/agent-feedback/7208
Verification
New
test/development/app-dir/catch-all-nested-routes(Turbopack only via@force-gate turbopack) covers:[[...slug]]and[...slug]apple-icon.pngIt failed before the fix (dev exited with
TurbopackInternalError). It passes with the fix, also with__NEXT_CACHE_COMPONENTS=true.Existing suites still pass with
pnpm test-dev-turbo:metadata-dynamic-routes,conflicting-page-segments,app-catch-all-optional,catchall-specificity,catchall-parallel-routes-group,parallel-routes-catchall*,interception-routes-root-catchall,interception-routes-multiple-catchall,parallel-routes-and-interception-catchall,optional-catchall-route-params.AppPageErrorrefactor, I re-ranmetadata-dynamic-routes(23/23) andparallel-routes-catchall*(9/10). The one failure,parallel-routes-catchall-specificity(expectsProfile, getsModal), also fails locally on unmodified canary (v16.5.0-canary.49) and on this PR's first commit, so it is unrelated to this change. CI on the first commit passed it.cargo test -p next-core --lib,cargo clippy -p next-core,cargo fmt --check: pass.Manual:
next buildon an app with[[...slug]]/opengraph-image.tsxstill fails withOptional catch-all must be the last part of the URL in route "/section/[[...slug]]/opengraph-image".Not run: the production-mode metadata suites, since build validation is unchanged.