Skip to content

fix(isr/prerender): skip app page cache writes and prevent publishing error boundary artifact if there are render errors - #2789

Open
NriotHrreion wants to merge 5 commits into
cloudflare:mainfrom
NriotHrreion:fix/issue-2783-isr-stores-error-cache
Open

fix(isr/prerender): skip app page cache writes and prevent publishing error boundary artifact if there are render errors#2789
NriotHrreion wants to merge 5 commits into
cloudflare:mainfrom
NriotHrreion:fix/issue-2783-isr-stores-error-cache

Conversation

@NriotHrreion

@NriotHrreion NriotHrreion commented Aug 2, 2026

Copy link
Copy Markdown

Closes #2783

What changed

hasCapturedRenderError() is added to the finalizers' options FinalizeAppPageHtmlCacheResponseOptions and ScheduleAppPageRscCacheWriteOptions.

  • Inside the finalizers' cache promises, a corresponding check is added to prevent ISR cache writes if there are render errors.
if (options.hasCapturedRenderError()) {
  options.isrDebug?.("Cache write skipped (render error)", key);
  return;
}
  • Inside the path of stale background regeneration, revalidatedOnError is wrapped by rscErrorTracker which has hasCapturedRenderError(), so this check can also guard the stale background regenerations.

  • This check is also added to the prerender process, which prevents the error boundary page from being published to the build artifact.

Testing

Corresponding tests are added or updated.

  • pnpm test tests/app-page-cache.test.ts tests/app-page-cache-render.test.ts tests/app-page-dispatch.test.ts tests/app-page-render.test.ts tests/prerender.test.ts
  • pnpm test tests/isr-cache.test.ts tests/fetch-cache.test.ts tests/kv-cache-handler.test.ts

This is my first contribution to vinext. Thanks for reviewing!

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f04eedaeb8

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/vinext/src/server/app-page-cache-finalizer.ts
@NriotHrreion

Copy link
Copy Markdown
Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 53086d0433

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/vinext/src/server/app-page-render.ts
@NriotHrreion

Copy link
Copy Markdown
Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e363352ae0

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/vinext/src/server/app-page-render.ts
Comment thread packages/vinext/src/server/app-page-render.ts
Rethrow captured RSC errors before returning prerender boundary responses
@NriotHrreion

Copy link
Copy Markdown
Author

@codex review

@NriotHrreion NriotHrreion changed the title fix(isr): skip app page cache writes if there are render errors fix(isr/prerender): skip app page cache writes and prevent publishing error boundary artifact if there are render errors Aug 2, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 822cd0a1df

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +1107 to +1108
const capturedRscError = getCapturedPrerenderFailure();
if (capturedRscError !== null) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Reject SSR-only failures during prerender recovery

When prerendering encounters an SSR-only failure—for example, a client component throws during SSR while the RSC render itself succeeds—renderAppPageHtmlStreamWithRecovery() can return a local error.tsx response with status 200, but getCapturedPrerenderFailure() returns null because it observes only the RSC tracker. This branch therefore publishes the boundary response, and build/prerender.ts treats it as successful and writes the HTML and Flight artifacts. Preserve the SSR recovery error and reject any such prerender response as well.

Useful? React with 👍 / 👎.

@NriotHrreion NriotHrreion Aug 2, 2026

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Uh I think this issue is beyond the scope of this PR.
The original issue #2783 only mentioned RSC error, and this PR only made changes to RSC error tracker.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I also found that Codex reviews are often over-scoped. A trick I've been using is putting Non-goals in the PR body to mitigate it, it helps (but not fully, this thing still goes ham especially with exhaustive on)

import type { ReactNode } from "react";
import type { ReactFormState } from "react-dom/client";
import type { NavigationContext } from "vinext/shims/navigation";
import { isPprFallbackShellAbortError } from "vinext/shims/ppr-fallback-shell";

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep the PPR helper off the common render graph

This value import makes every App Router request load and initialize the 291-line PPR fallback-state module, including its two AsyncLocalStorage registries, even when PPR/cache components are disabled. Gate on pprFallbackShellSignal before dynamically loading the feature-specific helper, or move the abort predicate into a lightweight module so ordinary requests do not pay this startup/module-graph cost.

AGENTS.md reference: AGENTS.md:L477-L483

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

App Router ISR stores a failed render as a status-200 cache entry when the error is thrown after the shell flushes

2 participants