Skip to content

Commit 056c57b

Browse files
authored
fix: only set request phase to "action" when actually running an action (#76993)
When running a server action, we want `requestStore.phase` to be set to `'action'`, because it makes `cookies()` mutable. However we were doing this in a pretty coarse-grained manner -- it was set at the beginning of `handleAction`, but wasn't always properly cleaned up in case of early returns that don't render anything (e.g. `{ type: 'not-found' }`). This PR fixes that -- we only set the phase to `'action'` while the action is running, and immediately switch it to `'render'` when it settles. Incidentally, early 'not-found' returns from `handleAction` are currently bugged (see #77012 for more context + fix), so we were also accidentally allowing mutatating cookies while rendering a response to an unrecognized action, which should be a 404, but is currently a 200 + a page render. but that's such a niche edge case that it's not really relevant to real usage.
1 parent 366b725 commit 056c57b

1 file changed

Lines changed: 29 additions & 20 deletions

File tree

packages/next/src/server/app-render/action-handler.ts

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -510,13 +510,9 @@ export async function handleAction({
510510
// that in the work store to be up-to-date for subsequent rendering.
511511
workStore.isDraftMode = requestStore.draftMode.isEnabled
512512

513-
requestStore.phase = 'render'
514-
515513
return generateFlight(...args)
516514
}
517515

518-
requestStore.phase = 'action'
519-
520516
// When running actions the default is no-store, you can still `cache: 'force-cache'`
521517
workStore.fetchCache = 'default-no-store'
522518

@@ -674,18 +670,22 @@ export async function handleAction({
674670
// Only warn if it's a server action, otherwise skip for other post requests
675671
warnBadServerActionRequest()
676672

677-
const actionReturnedState = await workUnitAsyncStorage.run(
678-
requestStore,
679-
action
680-
)
673+
let actionReturnedState: unknown
674+
requestStore.phase = 'action'
675+
try {
676+
actionReturnedState = await workUnitAsyncStorage.run(
677+
requestStore,
678+
action
679+
)
680+
} finally {
681+
requestStore.phase = 'render'
682+
}
681683

682684
formState = await decodeFormState(
683685
actionReturnedState,
684686
formData,
685687
serverModuleMap
686688
)
687-
688-
requestStore.phase = 'render'
689689
}
690690

691691
// Skip the fetch path
@@ -829,18 +829,22 @@ export async function handleAction({
829829
// Only warn if it's a server action, otherwise skip for other post requests
830830
warnBadServerActionRequest()
831831

832-
const actionReturnedState = await workUnitAsyncStorage.run(
833-
requestStore,
834-
action
835-
)
832+
let actionReturnedState: unknown
833+
requestStore.phase = 'action'
834+
try {
835+
actionReturnedState = await workUnitAsyncStorage.run(
836+
requestStore,
837+
action
838+
)
839+
} finally {
840+
requestStore.phase = 'render'
841+
}
836842

837843
formState = await decodeFormState(
838844
actionReturnedState,
839845
formData,
840846
serverModuleMap
841847
)
842-
843-
requestStore.phase = 'render'
844848
}
845849

846850
// Skip the fetch path
@@ -917,9 +921,15 @@ export async function handleAction({
917921
actionId!
918922
]
919923

920-
const returnVal = await workUnitAsyncStorage.run(requestStore, () =>
921-
actionHandler.apply(null, boundActionArguments)
922-
)
924+
let returnVal: unknown
925+
requestStore.phase = 'action'
926+
try {
927+
returnVal = await workUnitAsyncStorage.run(requestStore, () =>
928+
actionHandler.apply(null, boundActionArguments)
929+
)
930+
} finally {
931+
requestStore.phase = 'render'
932+
}
923933

924934
// For form actions, we need to continue rendering the page.
925935
if (isFetchAction) {
@@ -1017,7 +1027,6 @@ export async function handleAction({
10171027
// swallow error, it's gonna be handled on the client
10181028
}
10191029

1020-
requestStore.phase = 'render'
10211030
return {
10221031
type: 'done',
10231032
result: await generateFlight(req, ctx, requestStore, {

0 commit comments

Comments
 (0)