AI & Agent Dev Bug Sandbox logo
AI & Agent Dev Bug Sandbox
Back to Radar

Redirect() Silently Fails And Enters Infinite Render Loop On Client-Side Navigation To Fully Dynamic Route With CacheComponents Enabled

Clicking a client-side <Link> to a route that calls redirect() never navigates and spins at ~100% CPU when the route builds as fully dynamic (ƒ) under cacheComponents=true. The redirect is caught by RedirectBoundary but never commits, so router.replace is never called. Direct visits work; only production client navigations are affected.

highConfidence 75%Next.jsAffected V16.3.1Affected V16.3.3Affected V16.4.0-Canary.6

Origin Analysis

Next.js handles soft NEXT_REDIRECT exclusively in the render-phase RedirectBoundary. When cacheComponents=true and a route is fully dynamic via `export const instant = false` (or any top-level dynamic read without Suspense), the throwing tree has no committable fallback. React discards the render before commit, so HandleRedirect's useEffect never fires, and React retries the render indefinitely.
1. Create a Next.js app with `cacheComponents: true` in next.config. 2. Add a route `/redirect-blocking/page.jsx` with `export const instant = false;` and a default async component that does `await headers()` then `redirect('/target')`. 3. Build and start the app (`npm run build && npm start`). 4. From the home page, click a `<Link href="/redirect-blocking">`. 5. Observe the URL stays unchanged, no error appears, and the tab CPU usage climbs to ~100% indefinitely. 6. Navigate directly to the same URL via the address bar; it correctly redirects to `/target`.

Fixing Code Block

Edge Case Audit

This patch relies on the NEXT_REDIRECT digest being present as a string in the raw flight data. If the digest is embedded differently (e.g., in a binary stream or parsed object), it may be missed. Verify against a real payload before shipping. False positives could occur if unrelated strings contain 'NEXT_REDIRECT', so the parsing should be guarded. Test in all navigation modes (push, replace, back/forward) and with both cacheComponents on/off. Roll back by removing the added check and letting RedirectBoundary handle redirects as before, or temporarily set `cacheComponents: false` in next.config. Reapply after any Next.js upgrade because this file is internal and may change.

Ecosystem Topology