Skip to content

Commit 45a328a

Browse files
authored
avoid logging stacks for internal errors (#71575)
`NEXT_PAGE_EXPORT_ERROR` and `NEXT_STATIC_GEN_BAILOUT` shouldn't show up in failed build logs as they'll point to an internal stack not related to user code. This updates the code that throws the `ExportPageError` to instead exit the worker when `prerenderEarlyExit` is true (which is the default) so that the page export error doesn't leak into the outer error handler which is meant for user errors. For static generation bailout errors, we'll log the error message (if it exists) otherwise there's nothing to log as the stack would point to internal framework code. This also removes a redundant log that is already printed as a prerender error.
1 parent 8a905cf commit 45a328a

File tree

5 files changed

+20
-14
lines changed

5 files changed

+20
-14
lines changed

packages/next/src/export/worker.ts

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ import {
4848
import { needsExperimentalReact } from '../lib/needs-experimental-react'
4949
import { runWithCacheScope } from '../server/async-storage/cache-scope.external'
5050
import type { AppRouteRouteModule } from '../server/route-modules/app-route/module.compiled'
51+
import { isStaticGenBailoutError } from '../client/components/static-generation-bailout'
5152

5253
const envConfig = require('../shared/lib/runtime-config.external')
5354

@@ -433,16 +434,17 @@ export async function exportPages(
433434
if (attempt >= maxAttempts - 1) {
434435
// Log a message if we've reached the maximum number of attempts.
435436
// We only care to do this if maxAttempts was configured.
436-
if (maxAttempts > 0) {
437+
if (maxAttempts > 1) {
437438
console.info(
438439
`Failed to build ${pageKey} after ${maxAttempts} attempts.`
439440
)
440441
}
441442
// If prerenderEarlyExit is enabled, we'll exit the build immediately.
442443
if (nextConfig.experimental.prerenderEarlyExit) {
443-
throw new ExportPageError(
444+
console.error(
444445
`Export encountered an error on ${pageKey}, exiting the build.`
445446
)
447+
process.exit(1)
446448
} else {
447449
// Otherwise, this is a no-op. The build will continue, and a summary of failed pages will be displayed at the end.
448450
}
@@ -540,8 +542,21 @@ async function exportPage(
540542
`\nError occurred prerendering page "${input.path}". Read more: https://nextjs.org/docs/messages/prerender-error\n`
541543
)
542544

545+
// bailoutToCSRError errors should not leak to the user as they are not actionable; they're
546+
// a framework signal
543547
if (!isBailoutToCSRError(err)) {
544-
console.error(isError(err) && err.stack ? err.stack : err)
548+
// A static generation bailout error is a framework signal to fail static generation but
549+
// and will encode a reason in the error message. If there is a message, we'll print it.
550+
// Otherwise there's nothing to show as we don't want to leak an error internal error stack to the user.
551+
if (isStaticGenBailoutError(err)) {
552+
if (err.message) {
553+
console.error(`Error: ${err.message}`)
554+
}
555+
} else if (isError(err) && err.stack) {
556+
console.error(err.stack)
557+
} else {
558+
console.error(err)
559+
}
545560
}
546561

547562
return { error: true, duration: Date.now() - start, files: [] }

packages/next/src/server/app-render/dynamic-rendering.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -653,9 +653,7 @@ export function throwIfDisallowedDynamic(
653653
console.error(syncError)
654654
}
655655
// The actual error should have been logged when the sync access ocurred
656-
throw new StaticGenBailoutError(
657-
`Route "${route}" could not be prerendered.`
658-
)
656+
throw new StaticGenBailoutError()
659657
}
660658

661659
const dynamicErrors = dynamicValidation.dynamicErrors
@@ -664,9 +662,7 @@ export function throwIfDisallowedDynamic(
664662
console.error(dynamicErrors[i])
665663
}
666664

667-
throw new StaticGenBailoutError(
668-
`Route "${route}" could not be prerendered.`
669-
)
665+
throw new StaticGenBailoutError()
670666
}
671667

672668
if (!dynamicValidation.hasSuspendedDynamic) {

test/e2e/app-dir/dynamic-io-errors/dynamic-io-errors.platform-dynamic.test.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,6 @@ function runTests(options: { withMinification: boolean }) {
126126
'Error: Route "/" used `Math.random()` outside of `"use cache"` and without explicitly calling `await connection()` beforehand. See more info here: https://nextjs.org/docs/messages/next-prerender-random'
127127
)
128128
expectError('Error occurred prerendering page "/"')
129-
expectError('Error: Route "/" could not be prerendered.')
130129
expectError('exiting the build.')
131130
})
132131
})

test/e2e/app-dir/dynamic-io-errors/dynamic-io-errors.sync-dynamic.test.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,6 @@ function runTests(options: { withMinification: boolean }) {
124124

125125
expectError('Route "/" used `searchParams.foo`')
126126
expectError('Error occurred prerendering page "/"')
127-
expectError('Error: Route "/" could not be prerendered.')
128127
expectError('exiting the build.')
129128
})
130129
})
@@ -212,7 +211,6 @@ function runTests(options: { withMinification: boolean }) {
212211

213212
expectError('Route "/" used `searchParams.foo`')
214213
expectError('Error occurred prerendering page "/"')
215-
expectError('Error: Route "/" could not be prerendered.')
216214
expectError('exiting the build.')
217215
})
218216
})
@@ -300,7 +298,6 @@ function runTests(options: { withMinification: boolean }) {
300298

301299
expectError('Route "/" used `cookies().get(\'token\')`')
302300
expectError('Error occurred prerendering page "/"')
303-
expectError('Route "/" could not be prerendered.')
304301
expectError('exiting the build.')
305302
})
306303
})

test/e2e/app-dir/dynamic-io-errors/dynamic-io-errors.test.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,6 @@ function runTests(options: { withMinification: boolean }) {
337337
)
338338
}
339339
expectError('Error occurred prerendering page "/"')
340-
expectError('Error: Route "/" could not be prerendered.')
341340
expectError('exiting the build.')
342341
})
343342
})

0 commit comments

Comments
 (0)