Skip to content

Commit e3f8993

Browse files
jkuboclaude
andcommitted
fix(node): prevent logAndExitProcess from recursing on a broken pipe
logAndExitProcess writes the error to the console before shutting down. When stderr is a closed pipe that write raises EPIPE, which surfaces as another uncaught exception and re-enters the handler. calledFatalError is already set by then, so onuncaughtexception routes straight back into logAndExitProcess and the cycle repeats, allocating an Error with a captured stack and a pending client.close() on every pass until V8 aborts with a heap OOM. Guard the function itself rather than the calledFatalError branch, so every caller is covered. Fixes #24337 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1 parent fd00e5d commit e3f8993

1 file changed

Lines changed: 12 additions & 0 deletions

File tree

packages/node/src/utils/errorhandling.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,22 @@ import type { NodeClient } from '../sdk/client';
44

55
const DEFAULT_SHUTDOWN_TIMEOUT = 2000;
66

7+
let isShuttingDown = false;
8+
79
/**
810
* @hidden
911
*/
1012
export function logAndExitProcess(error: unknown): void {
13+
// A second failure while we are already shutting down must not re-enter.
14+
// The console.error below writes to stderr; when that stream is a broken
15+
// pipe the write throws EPIPE, which surfaces as another uncaught
16+
// exception and lands back here, recursing until the heap is exhausted.
17+
if (isShuttingDown) {
18+
global.process.exit(1);
19+
return;
20+
}
21+
isShuttingDown = true;
22+
1123
consoleSandbox(() => {
1224
// eslint-disable-next-line no-console
1325
console.error(error);

0 commit comments

Comments
 (0)