Skip to content

Commit 7425d51

Browse files
authored
Fix ServerAction rejection reason (#63744)
Recently the serverActionReducer was updated to no longer use React's thenable type to carry resolution/rejection information. However the rejection reason was not updated so now when a server action fails we were rejecting with `undefined` rather than the rejected reason. This change updates the reject to use the rejection value. Closes NEXT-2943
1 parent 2fc408d commit 7425d51

File tree

4 files changed

+48
-1
lines changed

4 files changed

+48
-1
lines changed

packages/next/src/client/components/router-reducer/reducers/server-action-reducer.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ export function serverActionReducer(
269269
},
270270
(e: any) => {
271271
// When the server action is rejected we don't update the state and instead call the reject handler of the promise.
272-
reject(e.reason)
272+
reject(e)
273273

274274
return state
275275
}

test/e2e/app-dir/actions/app-action.test.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,23 @@ createNextDescribe(
3939
await check(() => browser.elementById('count').text(), '3')
4040
})
4141

42+
it('should report errors with bad inputs correctly', async () => {
43+
const browser = await next.browser('/error-handling', {
44+
pushErrorAsConsoleLog: true,
45+
})
46+
47+
await browser.elementByCss('#submit').click()
48+
49+
const logs = await browser.log()
50+
expect(
51+
logs.some((log) =>
52+
log.message.includes(
53+
'Only plain objects, and a few built-ins, can be passed to Server Actions. Classes or null prototypes are not supported.'
54+
)
55+
)
56+
).toBe(true)
57+
})
58+
4259
it('should support headers and cookies', async () => {
4360
const browser = await next.browser('/header')
4461

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
'use server'
2+
3+
export async function action() {
4+
return 'action result'
5+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
'use client'
2+
3+
import { action } from './actions'
4+
5+
export default function Page() {
6+
return (
7+
<main>
8+
<p>
9+
This button will call a server action and pass something unserializable
10+
like a class instance. We expect this action to error with a reasonable
11+
message explaning what happened
12+
</p>
13+
<button
14+
id="submit"
15+
onClick={async () => {
16+
await action(new Foo())
17+
}}
18+
>
19+
Submit
20+
</button>
21+
</main>
22+
)
23+
}
24+
25+
class Foo {}

0 commit comments

Comments
 (0)