How to Fix: Root intercepting route with Edge runtime leads to root layout re-render with malformed params
When a root intercepting route runs on the Edge runtime, Next.js can re-render the root layout with corrupted route params, causing locale-aware apps to break in a way that looks random but is actually reproducible.
This issue commonly appears in apps using the App Router, root-level dynamic params such as [locale], and an intercepting route like (.) or related modal patterns. In the reported case, navigating into an intercepted route under Edge causes the root layout to render again with malformed params, which can break i18n logic, trigger wrong segment resolution, or surface runtime errors.
If you are debugging the issue described in this reproduction repository, the safest fix is to avoid combining root intercepting routes with Edge-rendered root dynamic layouts until the framework behavior is corrected, and to move the interception boundary deeper in the route tree or force the affected branch back to the Node runtime.
Symptoms
You are likely hitting this bug if all of the following are true:
- Your app uses the Next.js App Router.
- Your root route includes a dynamic segment such as
app/[locale]/layout.tsx. - You use an intercepting route for modal or overlay navigation.
- The route tree or layout is configured for the Edge runtime.
- Navigation into the intercepted route causes the root layout to re-render with unexpected
params, often malformed, missing, or structurally different from normal navigation.
Typical effects include:
- Incorrect locale detection.
- Unexpected root layout resets.
- Broken modal navigation.
- Server component errors due to invalid
params.locale. - Hydration or rendering inconsistencies between direct loads and client transitions.
Understanding the Root Cause
The bug is caused by an interaction between intercepting route resolution, root dynamic segment params, and the Edge runtime request pipeline.
In a normal App Router request, Next.js resolves the segment tree, extracts dynamic params like locale, and passes those params through layouts and pages in a predictable hierarchy. Intercepting routes complicate that process because they intentionally render content from another route branch while preserving part of the current layout tree. That means the router has to merge two ideas at once: the visible URL context and the intercepted segment context.
At the root level, this becomes fragile. If your root layout depends on a dynamic param such as [locale], and an intercepted route is evaluated under Edge, the framework can reconstruct the segment tree in a way that causes the root layout to run again with malformed param data. Instead of receiving the expected object shape, the layout may receive an incomplete or incorrectly derived param value.
Why Edge makes this more visible:
- Edge runtime uses a different execution environment from the Node runtime.
- The route matching and request handling path can differ enough to expose framework bugs that do not reproduce identically under Node.
- Because root layouts are foundational in the App Router, any mismatch in param propagation becomes immediately visible in locale-based routing.
In short, the problem is not usually your locale logic. The real issue is that root-level interception + dynamic root params + Edge runtime creates an unstable param propagation path.
Step-by-Step Solution
The most reliable workaround is to restructure the route tree so that interception happens below the dynamic root layout, or to stop running the affected branch on Edge.
1. Confirm the problematic combination
A typical problematic structure looks like this:
app/
[locale]/
layout.tsx
example/
page.tsx
@modal/
(.)item/
[id]/
page.tsx
If [locale]/layout.tsx or the intercepted route branch exports runtime = 'edge', and modal navigation triggers root layout re-rendering with bad params, you are in the affected scenario.
2. Move interception below the root dynamic segment
Instead of intercepting at a level that forces the root dynamic layout back into routing resolution, place the intercepted route inside a more stable subtree.
Refactor toward a structure like this:
app/
[locale]/
layout.tsx
example/
layout.tsx
page.tsx
@modal/
(.)item/
[id]/
page.tsx
item/
[id]/
page.tsx
This reduces the chance that the router has to rebuild the root layout context while resolving the interception.
3. Keep locale handling isolated in the root layout
Validate params defensively so malformed values fail fast and predictably.
export default function LocaleLayout({
children,
params,
}: {
children: React.ReactNode
params: { locale?: string }
}) {
const locale = params?.locale
if (!locale || !['en', 'fr', 'de'].includes(locale)) {
throw new Error('Invalid locale param in root layout')
}
return children
}
This does not fix the framework bug, but it makes diagnosis easier and prevents silent rendering under invalid state.
4. Force the affected route branch to the Node runtime
If restructuring is not immediately possible, switch the involved layout or page away from Edge.
export const runtime = 'nodejs'
Apply this in the smallest possible surface area, typically the intercepted route branch or the nearest layout that reproduces the issue. If the bug disappears under Node, that strongly confirms the Edge-specific behavior.
5. Avoid root-level modal interception for locale-prefixed apps
If your app uses URL-based i18n like /en/example, prefer modal interception under the feature route rather than from the app root. For example, render the modal from within example instead of defining an interception pattern that competes with the root locale segment.
// Good mental model:
// /[locale]/example manages its own modal interception
// instead of forcing root-level interception logic
6. Add a safe fallback for direct navigation
Intercepted routes should still have a non-modal canonical page so direct loads work independently of interception.
app/
[locale]/
example/
item/
[id]/
page.tsx
example/
@modal/
(.)item/
[id]/
page.tsx
This ensures that even if modal interception is bypassed or temporarily disabled, the destination route still renders correctly.
7. Test both client transitions and hard reloads
This bug often appears only during one navigation mode.
// Validate all of these manually:
// 1. Open /en/example directly
// 2. Click into intercepted modal route
// 3. Refresh while modal is open
// 4. Navigate back
// 5. Open canonical item page directly
If only the intercepted transition fails under Edge, your workaround is correctly targeting the routing interaction rather than general app state.
8. Example fix summary
// Before
// - root dynamic layout uses Edge
// - intercepting route crosses root context
// After
// - interception moved under /[locale]/example
// - or affected branch uses runtime = 'nodejs'
// - canonical non-intercepted route kept for direct access
Common Edge Cases
Locale middleware rewrites
If you also use middleware to rewrite locale paths, verify that the rewritten pathname still matches the intercepted route tree you expect. A middleware rewrite plus interception can make param bugs appear worse because the incoming URL and resolved route no longer align cleanly.
Parallel routes with missing default content
If your modal slot is a parallel route such as @modal, make sure it has a valid default state. Missing defaults can create confusing render behavior that looks like a params issue.
app/[locale]/example/@modal/default.tsx
export default function Default() {
return null
}
Static generation mixed with Edge runtime
If some branches use generateStaticParams while intercepted branches are rendered dynamically on Edge, verify that you are not mixing assumptions about param stability. Static params do not protect you from runtime param corruption during intercepted navigation.
Nested dynamic segments
The problem can get harder to trace when your route includes multiple dynamic segments like /[locale]/[tenant]/example. In that setup, malformed params may appear as shifted or incomplete keys rather than a single broken locale value.
Reading params too early in shared server utilities
If you pass params into shared server functions before validating them in the layout, a malformed value can trigger downstream failures that hide the actual routing bug. Validate close to the layout boundary first.
FAQ
Is this caused by bad i18n code in my root layout?
Usually no. If the issue only appears when using a root intercepting route on the Edge runtime, and standard navigation works correctly, the problem is more likely in framework-level param propagation than in your locale implementation.
Why does switching from Edge to Node fix it?
Because the bug is tied to how routing and rendering are resolved in the Edge runtime path. The Node runtime uses a different execution model, so the malformed root params may never be produced there.
What is the best long-term fix?
The best long-term fix is to keep interception scoped below the root dynamic segment, preserve a canonical non-intercepted route, and monitor the upstream framework issue for a proper patch. If you must ship immediately, use runtime = ‘nodejs’ for the affected branch.
For production apps, the practical recommendation is simple: do not let root-level intercepted navigation depend on Edge-resolved dynamic root params unless you have verified the behavior across direct loads, client transitions, refreshes, and locale rewrites.