Skip to content

Commit 9cac73c

Browse files
authored
Uninstall existing uncaughtException listeners to prevent the process from crashing (#78042)
This broadens the scope of the `removeUnhandledRejectionListeners` flag to also remove `uncaughtException` listeners. The motivation is the same: uncaught exceptions in one part of the page should not prevent the rest of the page from rendering. See #77997 for more context. I renamed the experimental flag to `removeUncaughtErrorAndRejectionListeners` to better reflect increased scope but the name isn't really that important since at this stage we just need to try out the behavior; it isn't documented anywhere.
1 parent fc134fc commit 9cac73c

File tree

3 files changed

+15
-14
lines changed

3 files changed

+15
-14
lines changed

packages/next/src/server/config-schema.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -390,7 +390,7 @@ export const configSchema: zod.ZodType<NextConfig> = z.lazy(() =>
390390
prerenderEarlyExit: z.boolean().optional(),
391391
proxyTimeout: z.number().gte(0).optional(),
392392
routerBFCache: z.boolean().optional(),
393-
removeUnhandledRejectionListeners: z.boolean().optional(),
393+
removeUncaughtErrorAndRejectionListeners: z.boolean().optional(),
394394
scrollRestoration: z.boolean().optional(),
395395
sri: z
396396
.object({

packages/next/src/server/config-shared.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -510,14 +510,14 @@ export interface ExperimentalConfig {
510510
routerBFCache?: boolean
511511

512512
/**
513-
* Uninstalls all "unhandledRejection" listeners from the global process so
514-
* that we can override the behavior, which in some runtimes is to exit the
515-
* process on an unhandled rejection.
513+
* Uninstalls all "unhandledRejection" and "uncaughtException" listeners from
514+
* the global process so that we can override the behavior, which in some
515+
* runtimes is to exit the process.
516516
*
517517
* This is experimental until we've considered the impact in various
518518
* deployment environments.
519519
*/
520-
removeUnhandledRejectionListeners?: boolean
520+
removeUncaughtErrorAndRejectionListeners?: boolean
521521

522522
serverActions?: {
523523
/**
@@ -1312,7 +1312,7 @@ export const defaultConfig: NextConfig = {
13121312
useEarlyImport: false,
13131313
viewTransition: false,
13141314
routerBFCache: false,
1315-
removeUnhandledRejectionListeners: false,
1315+
removeUncaughtErrorAndRejectionListeners: false,
13161316
staleTimes: {
13171317
dynamic: 0,
13181318
static: 300,

packages/next/src/server/next-server.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ function getMiddlewareMatcher(
161161
}
162162

163163
function installProcessErrorHandlers(
164-
shouldRemoveUnhandledRejectionListeners: boolean
164+
shouldRemoveUncaughtErrorAndRejectionListeners: boolean
165165
) {
166166
// The conventional wisdom of Node.js and other runtimes is to treat
167167
// unhandled errors as fatal and exit the process.
@@ -199,11 +199,12 @@ function installProcessErrorHandlers(
199199
// So, we're going to intentionally override the default error handling
200200
// behavior of the outer JS runtime to be more forgiving
201201

202-
// Remove any existing "unhandledRejection" handlers. This is gated behind
203-
// an experimental flag until we've considered the impact in various
204-
// deployment environments. It's possible this may always need to
202+
// Remove any existing "unhandledRejection" and "uncaughtException" handlers.
203+
// This is gated behind an experimental flag until we've considered the impact
204+
// in various deployment environments. It's possible this may always need to
205205
// be configurable.
206-
if (shouldRemoveUnhandledRejectionListeners) {
206+
if (shouldRemoveUncaughtErrorAndRejectionListeners) {
207+
process.removeAllListeners('uncaughtException')
207208
process.removeAllListeners('unhandledRejection')
208209
}
209210

@@ -370,10 +371,10 @@ export default class NextNodeServer extends BaseServer<
370371
populateStaticEnv(this.nextConfig)
371372
}
372373

373-
const shouldRemoveUnhandledRejectionListeners = Boolean(
374-
options.conf.experimental?.removeUnhandledRejectionListeners
374+
const shouldRemoveUncaughtErrorAndRejectionListeners = Boolean(
375+
options.conf.experimental?.removeUncaughtErrorAndRejectionListeners
375376
)
376-
installProcessErrorHandlers(shouldRemoveUnhandledRejectionListeners)
377+
installProcessErrorHandlers(shouldRemoveUncaughtErrorAndRejectionListeners)
377378
}
378379

379380
public async unstable_preloadEntries(): Promise<void> {

0 commit comments

Comments
 (0)