Skip to content

Commit 432d119

Browse files
authored
Fix missing error message in terminal for bound args serialization error (#73508)
This is a small follow-up to #73471. The error message got lost when assigning the custom stack (the message is usually also part of the stack). This was only noticeable in the Terminal though; the dev overlay showed the error correctly. We're now adding assertions on the CLI output to the e2e test. In addition, the custom stack slicing is replaced with `Error.captureStackTrace` (h/t @eps1lon).
1 parent eb4cd43 commit 432d119

File tree

2 files changed

+43
-14
lines changed

2 files changed

+43
-14
lines changed

packages/next/src/server/app-render/encryption.ts

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -73,33 +73,32 @@ async function encodeActionBoundArg(actionId: string, arg: string) {
7373
export async function encryptActionBoundArgs(actionId: string, args: any[]) {
7474
const { clientModules } = getClientReferenceManifestForRsc()
7575

76-
// An error stack that's created here looks like this:
77-
// Error:
78-
// at encryptActionBoundArg
79-
// at <actual userland call site>
80-
const stack = new Error().stack!.split('\n').slice(2).join('\n')
76+
// Create an error before any asynchrounous calls, to capture the original
77+
// call stack in case we need it when the serialization errors.
78+
const error = new Error()
79+
Error.captureStackTrace(error, encryptActionBoundArgs)
8180

82-
let error: Error | undefined
81+
let didCatchError = false
8382

8483
// Using Flight to serialize the args into a string.
8584
const serialized = await streamToString(
8685
renderToReadableStream(args, clientModules, {
8786
onError(err) {
8887
// We're only reporting one error at a time, starting with the first.
89-
if (error) {
88+
if (didCatchError) {
9089
return
9190
}
9291

93-
// Use the original error message...
94-
error = err instanceof Error ? err : new Error(String(err))
95-
// ...and attach the previously created stack, because err.stack is a
96-
// useless Flight Server call stack.
97-
error.stack = stack
92+
didCatchError = true
93+
94+
// Use the original error message together with the previously created
95+
// stack, because err.stack is a useless Flight Server call stack.
96+
error.message = err instanceof Error ? err.message : String(err)
9897
},
9998
})
10099
)
101100

102-
if (error) {
101+
if (didCatchError) {
103102
if (process.env.NODE_ENV === 'development') {
104103
// Logging the error is needed for server functions that are passed to the
105104
// client where the decryption is not done during rendering. Console

test/e2e/app-dir/use-cache-close-over-function/use-cache-close-over-function.test.ts

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import {
77
} from 'next-test-utils'
88

99
describe('use-cache-close-over-function', () => {
10-
const { next, isNextDev, skipped } = nextTestSetup({
10+
const { next, isNextDev, isTurbopack, skipped } = nextTestSetup({
1111
files: __dirname,
1212
skipDeployment: true,
1313
skipStart: process.env.NEXT_TEST_MODE !== 'dev',
@@ -43,6 +43,21 @@ describe('use-cache-close-over-function', () => {
4343
10 | return Math.random() + fn()
4444
11 | }"
4545
`)
46+
47+
if (isTurbopack) {
48+
expect(next.cliOutput).toInclude(`
49+
⨯ Error: Functions cannot be passed directly to Client Components unless you explicitly expose it by marking it with "use server". Or maybe you meant to call this function rather than return it.
50+
[function fn]
51+
^^^^^^^^^^^
52+
at createCachedFn (./app/client/page.tsx:8:3)`)
53+
} else {
54+
// TODO(veil): line:column is wrong with Webpack.
55+
expect(next.cliOutput).toInclude(`
56+
⨯ Error: Functions cannot be passed directly to Client Components unless you explicitly expose it by marking it with "use server". Or maybe you meant to call this function rather than return it.
57+
[function fn]
58+
^^^^^^^^^^^
59+
at createCachedFn (./app/client/page.tsx:25:132)`)
60+
}
4661
})
4762

4863
it('should show the error overlay for server-side usage', async () => {
@@ -70,6 +85,21 @@ describe('use-cache-close-over-function', () => {
7085
8 | return Math.random() + fn()
7186
9 | }"
7287
`)
88+
89+
if (isTurbopack) {
90+
expect(next.cliOutput).toInclude(`
91+
⨯ Error: Functions cannot be passed directly to Client Components unless you explicitly expose it by marking it with "use server". Or maybe you meant to call this function rather than return it.
92+
[function fn]
93+
^^^^^^^^^^^
94+
at createCachedFn (./app/server/page.tsx:6:3)`)
95+
} else {
96+
// TODO(veil): line:column is wrong with Webpack.
97+
expect(next.cliOutput).toInclude(`
98+
⨯ Error: Functions cannot be passed directly to Client Components unless you explicitly expose it by marking it with "use server". Or maybe you meant to call this function rather than return it.
99+
[function fn]
100+
^^^^^^^^^^^
101+
at createCachedFn (./app/server/page.tsx:23:132)`)
102+
}
73103
})
74104
} else {
75105
it('should fail the build with an error', async () => {

0 commit comments

Comments
 (0)