Skip to content

fix : server actions POST to return RSC payload#91669

Closed
nehaaprasad wants to merge 2 commits intovercel:canaryfrom
nehaaprasad:fix/ser-act-ret-text-rsc-payl
Closed

fix : server actions POST to return RSC payload#91669
nehaaprasad wants to merge 2 commits intovercel:canaryfrom
nehaaprasad:fix/ser-act-ret-text-rsc-payl

Conversation

@nehaaprasad
Copy link
Copy Markdown
Contributor

What?

  • Fix Server Action POST to return RSC payload, not HTML.

Why?

  • 16.2.0 could return HTML for action POST in PPR + cacheComponents, causing E394.

How?

  • Treat possible Server Action requests as RSC in app page response handling.

Fixes : #91662

@nextjs-bot
Copy link
Copy Markdown
Collaborator

nextjs-bot commented Mar 19, 2026

Allow CI Workflow Run

  • approve CI run for commit: 2c849f5

Note: this should only be enabled once the PR is ready to go and can only be enabled by a maintainer

Comment on lines +1644 to +1646
// return the generated payload. Server Action POSTs expect RSC payload
// but do not send the RSC header, so we treat them as RSC requests here.
if ((isRSCRequest || isPossibleServerAction) && !isDraftMode) {
Copy link
Copy Markdown
Contributor

@vercel vercel bot Mar 19, 2026

Choose a reason for hiding this comment

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

The condition (isRSCRequest || isPossibleServerAction) && !isDraftMode incorrectly routes HTML responses from MPA server actions and false-positive form POSTs into the RSC serving path, causing either 404 responses (with cacheComponents) or InvariantError throws.

Fix on Vercel

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

I tested this with my example project for this error #91662 and I indeed now get a 404 Error for a valid server action

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.

Thanks for confirming @lucasra1 — that matches the analysis. The root cause is that isPossibleServerAction is a broad heuristic (true for any multipart/form-data or application/x-www-form-urlencoded POST), so it matches MPA form submissions and non-action POSTs that produce HTML responses. When those HTML responses enter the RSC branch, they fail the content type check and 404.

The suggested fix above guards the isPossibleServerAction path with an additional check that the response actually contains RSC content (rscData is defined or html.contentType is the RSC content type), so only fetch-based server actions that genuinely produce RSC payloads take this path.

unstubbable added a commit that referenced this pull request Mar 20, 2026
The `staticPathKey` condition added in #91231 inadvertently applies to
server action requests on dynamic SSG routes when `cacheComponents` is
enabled.

Server action fetch requests from the client do not send the `RSC`
header (`rsc: 1`). They only send `Accept: text/x-component` and the
`Next-Action` header. This means `isRSCRequest` and
`isDynamicRSCRequest` are both `false` for action requests. The new
`staticPathKey` condition (`isSSG && pageIsDynamic &&
prerenderInfo?.fallbackRouteParams`) evaluates to `true` for dynamic PPR
routes, setting `staticPathKey` even though `ssgCacheKey` is `null` for
actions.

With `staticPathKey` set, the request enters the fallback rendering
block, which serves the cached fallback HTML shell with the action
result appended to it, instead of responding with just the RSC action
result.

The fix excludes server action requests from the `staticPathKey`
computation by adding `!isPossibleServerAction` to the condition,
restoring the pre-#91231 behavior where `staticPathKey` was always
`null` for server actions in production.

fixes #91662
closes #91677
closes #91669
unstubbable added a commit that referenced this pull request Mar 20, 2026
The `staticPathKey` condition added in #91231 inadvertently applies to
server action requests on dynamic SSG routes when `cacheComponents` is
enabled.

Server action fetch requests from the client do not send the `RSC`
header (`rsc: 1`). They only send `Accept: text/x-component` and the
`Next-Action` header. This means `isRSCRequest` and
`isDynamicRSCRequest` are both `false` for action requests. The new
`staticPathKey` condition (`isSSG && pageIsDynamic &&
prerenderInfo?.fallbackRouteParams`) evaluates to `true` for dynamic PPR
routes, setting `staticPathKey` even though `ssgCacheKey` is `null` for
actions.

With `staticPathKey` set, the request enters the fallback rendering
block, which serves the cached fallback HTML shell with the action
result appended to it, instead of responding with just the RSC action
result.

The fix excludes server action requests from the `staticPathKey`
computation by adding `!isPossibleServerAction` to the condition,
restoring the pre-#91231 behavior where `staticPathKey` was always
`null` for server actions in production.

fixes #91662
closes #91677
closes #91669
ijjk pushed a commit that referenced this pull request Mar 20, 2026
The `staticPathKey` condition added in #91231 inadvertently applies to
server action requests on dynamic SSG routes when `cacheComponents` is
enabled.

Server action fetch requests from the client do not send the `RSC`
header (`rsc: 1`). They only send `Accept: text/x-component` and the
`Next-Action` header. This means `isRSCRequest` and
`isDynamicRSCRequest` are both `false` for action requests. The new
`staticPathKey` condition (`isSSG && pageIsDynamic &&
prerenderInfo?.fallbackRouteParams`) evaluates to `true` for dynamic PPR
routes, setting `staticPathKey` even though `ssgCacheKey` is `null` for
actions.

With `staticPathKey` set, the request enters the fallback rendering
block, which serves the cached fallback HTML shell with the action
result appended to it, instead of responding with just the RSC action
result.

The fix excludes server action requests from the `staticPathKey`
computation by adding `!isPossibleServerAction` to the condition,
restoring the pre-#91231 behavior where `staticPathKey` was always
`null` for server actions in production.

fixes #91662
closes #91677
closes #91669
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Server Action POST returns text/html PPR shell instead of RSC payload after upgrading to 16.2.0

3 participants