-
Notifications
You must be signed in to change notification settings - Fork 30.2k
fix: handle notFound in Suspense with cacheComponents enabled #87041
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: canary
Are you sure you want to change the base?
fix: handle notFound in Suspense with cacheComponents enabled #87041
Conversation
|
Allow CI Workflow Run
Note: this should only be enabled once the PR is ready to go and can only be enabled by a maintainer |
|
Excellent fix for a tricky edge case! 🎯 Problem Identified: Solution Approach:
Strengths: Minor Suggestions:
Overall, this is a solid fix for a complex streaming + error handling interaction! 🚀 |
|
We are experiencing this and it is pretty much a deal killer for being able to use cache components as it essentially means we can have any working 404 behavior on pages. Hoping @Rani367's fix makes it into the next release soon. import { notFound } from 'next/navigation'
export default async function ArticlePage({ params }: { params: Promise<{ slug: string }> }) {
const { slug } = await params
const article = await findArticle(slug)
if (!article) {
notFound() // results in connection closed and error page instead of 404
}
return <article />
} |
|
Hi @gnoff, could you take a look at this PR when you have a chance? There are users blocked by this issue (see #86251 and the comment above from @dsbrianwebster) who can't use |
5f3bc67 to
ec2b374
Compare
When cacheComponents is enabled and a page is prerendered, subsequent requests use DynamicState.DATA mode which only sends RSC data without re-rendering the HTML shell. However, when notFound() (or forbidden/ unauthorized) is thrown during this RSC render, the prerendered HTML doesn't contain the not-found component, causing Connection closed errors. This fix buffers the RSC stream in DATA mode to detect HTTP access fallback errors. If such errors are found, it falls through to the full dynamic render path which properly handles the not-found page. Fixes vercel#86251
ec2b374 to
8a7df5b
Compare
|
Updated the fix to also store HTTP access fallback errors in reactServerErrorsByDigest (in create-error-handler.tsx), which is needed for the detection logic in app-render.tsx to work correctly. |
What?
This PR fixes an issue where
notFound()(and other HTTP access fallback errors likeforbidden()/unauthorized()) would cause "Connection closed" errors whencacheComponents: trueis enabled and the page has a Suspense boundary with an async component.Why?
When
cacheComponentsis enabled and a page is prerendered, subsequent requests useDynamicState.DATAmode which only sends RSC data without re-rendering the HTML shell. However, whennotFound()is thrown during this RSC render, the prerendered HTML doesn't contain the not-found component, causing the client to receive an incomplete stream and display "Connection closed" errors.How?
This fix buffers the RSC stream in
DynamicState.DATAmode to detect HTTP access fallback errors. After consuming the stream:reactServerErrorsByDigestfor any errors with theHTTP_ERROR_FALLBACK_ERROR_CODEprefixTest Plan
Added two test cases:
not-found-suspense: TestsnotFound()thrown inside a Suspense boundarynot-found-with-layout-suspense: Exact reproduction of the issue -notFound()in page with async component in layout's SuspenseFixes #86251