mirror of
https://github.com/cloudflare/vinext.git
synced 2026-05-09 08:25:34 +02:00
[PR #985] [MERGED] fix(app-router): return action-not-found for stale server actions #1002
Labels
No labels
enhancement
enhancement
good first issue
help wanted
nextjs-tracking
nextjs-tracking
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
starred/vinext#1002
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
📋 Pull Request Information
Original PR: https://github.com/cloudflare/vinext/pull/985
Author: @NathanDrake2406
Created: 4/30/2026
Status: ✅ Merged
Merged: 4/30/2026
Merged by: @james-elicx
Base:
main← Head:nathan/server-action-not-found📝 Commits (2)
7bf5d4afix(app-router): return action-not-found for stale server actions8d5c6ecchore: rerun ci📊 Changes
5 files changed (+240 additions, -10 deletions)
View changed files
📝
packages/vinext/src/server/app-browser-entry.ts(+8 -0)📝
packages/vinext/src/server/app-server-action-execution.ts(+51 -2)➕
packages/vinext/src/server/server-action-not-found.ts(+58 -0)📝
tests/app-router.test.ts(+7 -7)📝
tests/app-server-action-execution.test.ts(+116 -1)📄 Description
What this changes
Vinext now returns the Next.js action-not-found protocol for unknown or stale App Router Server Action ids:
404response statusx-nextjs-action-not-found: 1Server action not found.response bodyWhy
Stale Server Action ids can happen during deployment skew or from an older client tab. Before this change,
loadServerAction()failures fell through the generic server action error reporter and returned500, which made expected skew look like an application failure and skipped the client recovery signal.Next.js treats this as a dedicated not-found protocol:
handleUnrecognizedFetchActiongetActionModIdOrErrorcall andgetActionModIdOrErrorx-nextjs-action-not-found:server-action-reducer.tsno-server-actions.test.tsApproach
The action-not-found behavior is implemented in a normal runtime module,
server-action-not-found.ts, and the generated/runtime entry paths only wire through that behavior. This keeps with the project rule that codegen describes app shape while normal modules implement behavior.The RSC action helper now treats
loadServerAction()as an external runtime boundary returningunknown, narrows it before invocation, and maps only recognized missing-action cases to the action-not-found response. Unrelated loader failures still go through the existing generic 500 reporter path.Validation
vp test run tests/app-server-action-execution.test.tsvp test run tests/app-router.test.ts -t "allows server action POST"vp test run tests/app-server-action-execution.test.ts tests/app-router.test.ts -t "allows server action POST|stale fetch action ids|progressive action decode misses|server action export is missing|unrelated server action loader failures"vp run vinext#buildvp checkNote: in this fresh worktree, running
vp checkbeforevp run vinext#buildfailed becausebenchmarks/vinext/vite.config.tscould not resolve the workspacevinextpackage. After the package build created the local dist artifacts,vp checkpassed cleanly.Risks / follow-ups
The missing-action classifier is intentionally narrow: it recognizes Next.js' failed-action messages and Vite RSC's invalid server reference message, while preserving generic loader failures as 500s. Malformed action payload validation still runs before action lookup in Vinext to preserve the existing payload-hardening behavior.
🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.