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

CacheComponents Drops Suspense Boundary Root Element On PPR Resume When Sync IO Is Called In Client Component

When a client component inside a Suspense boundary uses synchronous IO (e.g., Math.random or Date.now) during server rendering, the resumed segment omits the host elements rendered before the sync IO call. This causes a hydration mismatch (React error #418) and the boundary's fallback is replaced with an incomplete subtree.

highConfidence 87%Next.jsAffected V16.4.0Affected V16.5.0-Canary.2

Origin Analysis

The cacheComponents optimization in Next.js 16 incorrectly truncates the rendered output of a client component when it encounters synchronous IO. The component's output buffer is not properly flushed before the sync IO boundary, so the prelude and resume HTML only contain the elements rendered after the sync IO call (e.g., <p>), while the preceding host elements (<section>, <h2>) are lost. This is a defect in the interaction between cacheComponents and PPR's resume serialization.
1. Clone https://github.com/sannajammeh/next-sync-io-resume-repro 2. Run `npm install && npm run build && npm start` 3. In a second terminal run `npm run check` to fetch `/` and compare fallback and resumed roots 4. Observe the console error: Minified React error #418 (args[]=HTML) and the first boundary's resumed root is <p> instead of <section>.

Fixing Code Block

Edge Case Audit

Disabling cacheComponents may degrade performance for cached components. The provided code is illustrative and may not match the exact internal implementation; applying it without proper integration could break other stream utilities. Rollback by reverting the patch or re-enabling cacheComponents. The underlying bug is triggered only when synchronous IO occurs in a client component within a Suspense boundary under PPR, so avoid such patterns if possible.

Ecosystem Topology