-
Notifications
You must be signed in to change notification settings - Fork 27.1k
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
Dynamic IO: Improve error handling #73607
Conversation
This stack of pull requests is managed by Graphite. Learn more about stacking. |
Stats from current PRDefault Build (Increase detected
|
vercel/next.js canary | vercel/next.js hl/dynamic-io-improve-error-handling | Change | |
---|---|---|---|
buildDuration | 20.4s | 17.6s | N/A |
buildDurationCached | 16.9s | 14.8s | N/A |
nodeModulesSize | 409 MB | 409 MB | |
nextStartRea..uration (ms) | 475ms | 476ms | N/A |
Client Bundles (main, webpack)
vercel/next.js canary | vercel/next.js hl/dynamic-io-improve-error-handling | Change | |
---|---|---|---|
1187-HASH.js gzip | 50.1 kB | 50.1 kB | N/A |
8276.HASH.js gzip | 169 B | 168 B | N/A |
8377-HASH.js gzip | 5.3 kB | 5.3 kB | N/A |
bccd1874-HASH.js gzip | 53 kB | 53 kB | N/A |
framework-HASH.js gzip | 57.5 kB | 57.5 kB | N/A |
main-app-HASH.js gzip | 232 B | 233 B | N/A |
main-HASH.js gzip | 33.7 kB | 33.7 kB | N/A |
webpack-HASH.js gzip | 1.71 kB | 1.71 kB | N/A |
Overall change | 0 B | 0 B | ✓ |
Legacy Client Bundles (polyfills)
vercel/next.js canary | vercel/next.js hl/dynamic-io-improve-error-handling | Change | |
---|---|---|---|
polyfills-HASH.js gzip | 39.4 kB | 39.4 kB | ✓ |
Overall change | 39.4 kB | 39.4 kB | ✓ |
Client Pages
vercel/next.js canary | vercel/next.js hl/dynamic-io-improve-error-handling | Change | |
---|---|---|---|
_app-HASH.js gzip | 193 B | 193 B | ✓ |
_error-HASH.js gzip | 193 B | 193 B | ✓ |
amp-HASH.js gzip | 513 B | 511 B | N/A |
css-HASH.js gzip | 343 B | 342 B | N/A |
dynamic-HASH.js gzip | 1.84 kB | 1.84 kB | N/A |
edge-ssr-HASH.js gzip | 265 B | 265 B | ✓ |
head-HASH.js gzip | 363 B | 362 B | N/A |
hooks-HASH.js gzip | 393 B | 392 B | N/A |
image-HASH.js gzip | 4.44 kB | 4.43 kB | N/A |
index-HASH.js gzip | 268 B | 268 B | ✓ |
link-HASH.js gzip | 2.35 kB | 2.34 kB | N/A |
routerDirect..HASH.js gzip | 328 B | 328 B | ✓ |
script-HASH.js gzip | 397 B | 397 B | ✓ |
withRouter-HASH.js gzip | 323 B | 326 B | N/A |
1afbb74e6ecf..834.css gzip | 106 B | 106 B | ✓ |
Overall change | 1.75 kB | 1.75 kB | ✓ |
Client Build Manifests
vercel/next.js canary | vercel/next.js hl/dynamic-io-improve-error-handling | Change | |
---|---|---|---|
_buildManifest.js gzip | 746 B | 747 B | N/A |
Overall change | 0 B | 0 B | ✓ |
Rendered Page Sizes
vercel/next.js canary | vercel/next.js hl/dynamic-io-improve-error-handling | Change | |
---|---|---|---|
index.html gzip | 523 B | 524 B | N/A |
link.html gzip | 537 B | 537 B | ✓ |
withRouter.html gzip | 519 B | 521 B | N/A |
Overall change | 537 B | 537 B | ✓ |
Edge SSR bundle Size Overall increase ⚠️
vercel/next.js canary | vercel/next.js hl/dynamic-io-improve-error-handling | Change | |
---|---|---|---|
edge-ssr.js gzip | 128 kB | 128 kB | N/A |
page.js gzip | 202 kB | 203 kB | |
Overall change | 202 kB | 203 kB |
Middleware size
vercel/next.js canary | vercel/next.js hl/dynamic-io-improve-error-handling | Change | |
---|---|---|---|
middleware-b..fest.js gzip | 667 B | 665 B | N/A |
middleware-r..fest.js gzip | 155 B | 156 B | N/A |
middleware.js gzip | 31 kB | 31 kB | N/A |
edge-runtime..pack.js gzip | 844 B | 844 B | ✓ |
Overall change | 844 B | 844 B | ✓ |
Next Runtimes Overall increase ⚠️
vercel/next.js canary | vercel/next.js hl/dynamic-io-improve-error-handling | Change | |
---|---|---|---|
797-experime...dev.js gzip | 322 B | 322 B | ✓ |
797.runtime.dev.js gzip | 314 B | 314 B | ✓ |
app-page-exp...dev.js gzip | 322 kB | 322 kB | |
app-page-exp..prod.js gzip | 127 kB | 127 kB | N/A |
app-page-tur..prod.js gzip | 139 kB | 140 kB | N/A |
app-page-tur..prod.js gzip | 135 kB | 135 kB | N/A |
app-page.run...dev.js gzip | 312 kB | 312 kB | |
app-page.run..prod.js gzip | 122 kB | 122 kB | N/A |
app-route-ex...dev.js gzip | 36.8 kB | 37.1 kB | |
app-route-ex..prod.js gzip | 25 kB | 25.1 kB | |
app-route-tu..prod.js gzip | 25 kB | 25.1 kB | |
app-route-tu..prod.js gzip | 24.8 kB | 24.9 kB | |
app-route.ru...dev.js gzip | 38.4 kB | 38.7 kB | |
app-route.ru..prod.js gzip | 24.8 kB | 24.9 kB | |
pages-api-tu..prod.js gzip | 9.56 kB | 9.56 kB | ✓ |
pages-api.ru...dev.js gzip | 11.4 kB | 11.4 kB | ✓ |
pages-api.ru..prod.js gzip | 9.56 kB | 9.56 kB | ✓ |
pages-turbo...prod.js gzip | 21.3 kB | 21.3 kB | ✓ |
pages.runtim...dev.js gzip | 27 kB | 27 kB | ✓ |
pages.runtim..prod.js gzip | 21.3 kB | 21.3 kB | ✓ |
server.runti..prod.js gzip | 916 kB | 916 kB | ✓ |
Overall change | 1.83 MB | 1.83 MB |
build cache Overall increase ⚠️
vercel/next.js canary | vercel/next.js hl/dynamic-io-improve-error-handling | Change | |
---|---|---|---|
0.pack gzip | 2.03 MB | 2.04 MB | |
index.pack gzip | 146 kB | 146 kB | N/A |
Overall change | 2.03 MB | 2.04 MB |
Diff details
Diff for main-HASH.js
Diff too large to display
Diff for app-page-exp..ntime.dev.js
Diff too large to display
Diff for app-page-exp..time.prod.js
Diff too large to display
Diff for app-page-tur..time.prod.js
Diff too large to display
Diff for app-page-tur..time.prod.js
Diff too large to display
Diff for app-page.runtime.dev.js
Diff too large to display
Diff for app-page.runtime.prod.js
Diff too large to display
Diff for app-route-ex..ntime.dev.js
Diff too large to display
Diff for app-route-ex..time.prod.js
Diff too large to display
Diff for app-route-tu..time.prod.js
Diff too large to display
Diff for app-route-tu..time.prod.js
Diff too large to display
Diff for app-route.runtime.dev.js
Diff too large to display
Diff for app-route.ru..time.prod.js
Diff too large to display
notFound
with dynamicIO
Failing test suitesCommit: f0fd675
Expand output● ReactRefreshLogBox app default › server component can recover from error thrown in the module
Read more about building and testing Next.js in contributing.md. |
export function getDigestForWellKnownError(error: unknown): string | undefined { | ||
// If we're bailing out to CSR, we don't need to log the error. | ||
if (isBailoutToCSRError(error)) return error.digest | ||
|
||
// If this is a navigation error, we don't need to log the error. | ||
if (isNextRouterError(error)) return error.digest | ||
|
||
// If this error occurs, we know that we should be stopping the static | ||
// render. This is only thrown in static generation when PPR is not enabled, | ||
// which causes the whole page to be marked as dynamic. We don't need to | ||
// tell the user about this error, as it's not actionable. | ||
if (isDynamicServerError(error)) return error.digest | ||
|
||
return undefined | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if it's time to brand our errors so we don't have to do these delimited type checks. Is the semantic we're going for that we want to forward digests from errors that the framework created? This is important because we don't want a userland error with a digest property to hit this pathway. We can use instanceof checks I suppose. One thing to consider is that this function might only work in RSC layer b/c if any of these predicates check instance identity it won't work across the serialization boundary whereas a digest check will surivive since React forwards those.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess it is also used on the client so they all have to check digest exclusively. This does mean it is relatively easy to create your own errors that appear to match these error types. Unlikely that this would actually happen but one way we can defend against that is for errors in RSC to never respect a passed in digest, only set the digest from some other source. Then the client can trust that a matching digest was always produced by the framework
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's tricky, we currently also need to preserve digests from the Cache
environment.
|
||
// This is intentionally using the readable datastream from the main | ||
// render rather than the flight data from the error page render | ||
const flightStream = | ||
reactServerPrerenderResult instanceof ServerPrerenderStreamResult | ||
? reactServerPrerenderResult.asStream() | ||
: reactServerPrerenderResult.consumeAsStream() | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The error handling pathway needs to be moved into the implementations of DIO X PPR so we can avoid stuff like this. It's fine to land for now but it just shows how brittle the current construction is. Lmk if you want to take that on :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought the 4-way branching is supposed to be temporary, so this prerender result union type would then also go away when we merge the branches again. But I guess that won't happen soon?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
well I think the error handling is also imprecise now b/c we should probably handle a fatal error in the RSC render differentaly than just not producing a shell in the SSR pass. At the moment it's all a little confused. We also need to ideally render the not found and error responses using DIO semantics so we might need to extract each branch into it's own implementation that can be called into again from within certain error cases. We can denormalize into each branch so that when we finally delete the unused ones we know we have only the necessary error handling semantics whereas today it is all sort of jumbled together
8780549
to
886742a
Compare
1915f89
to
2772f8e
Compare
886742a
to
3c39bcd
Compare
3c39bcd
to
6500c85
Compare
6500c85
to
f0fd675
Compare
This PR improves error handling when
dynamicIO
is enabled.notFound
used in the top level can be prerendered staticallyaddresses #73210 (comment)
closes NAR-48