Skip to content

child_process: clear timeout timer on spawn-time error too - #65506

Open
kishore280 wants to merge 3 commits into
nodejs:mainfrom
kishore280:fix/spawn-timeout-clear-on-error
Open

child_process: clear timeout timer on spawn-time error too#65506
kishore280 wants to merge 3 commits into
nodejs:mainfrom
kishore280:fix/spawn-timeout-clear-on-error

Conversation

@kishore280

Copy link
Copy Markdown

timeout's only cleanup was child.once('exit', clearTimeout). A spawn-time failure (ENOENT etc.) only emits error, never exit, so the timer stayed armed for the full timeout duration. Clear it on error too.

Checked: doesn't double-fire or race with the timeout's own kill-failure path (try { child.kill() } catch { child.emit('error') }). That emit('error') runs synchronously before the timeout callback's own timeoutId = null, so clearSpawnTimeout sees the already-fired timer id and calls clearTimeout on it - a documented no-op. The callback's own null-assignment right after is then redundant but harmless.

Fixes: #65504

When spawn() fails at the OS level (ENOENT, EACCES, EAGAIN, EMFILE,
ENFILE), the resulting ChildProcess only ever emits 'error', never
'exit'. The `timeout` option's cleanup only listened for 'exit', so
the timer stayed armed for the full `timeout` duration on any
spawn-time failure, holding the event loop open well after the
promise/callback had already settled via 'error'.

Clear the timer on 'error' as well as 'exit'.

Fixes: nodejs#65504
Signed-off-by: kishore280 <maheshwarankishore@gmail.com>
@nodejs-github-bot nodejs-github-bot added child_process Issues and PRs related to the child_process subsystem. needs-ci PRs that need a full CI run. labels Aug 23, 2026
'close' fires after 'exit' or 'error', so one listener is enough.

The old 'error' listener also had a side effect I didn't intend:
it quietly stopped Node's 'Unhandled error event' crash for anyone
using timeout without their own error handler. Not this fix's job.

Signed-off-by: kishore280 <maheshwarankishore@gmail.com>
@StefanStojanovic StefanStojanovic added the request-ci Add this label to start a Jenkins CI on a PR. label Aug 24, 2026
@github-actions github-actions Bot removed the request-ci Add this label to start a Jenkins CI on a PR. label Aug 24, 2026
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@@ -0,0 +1,22 @@
'use strict';

// Measures the child's actual exit time, not just its 'error' event - the outer spawnSync timeout catches a leaked inner timer.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line has a length of 128. Maximum allowed is 120.

Suggested change
// Measures the child's actual exit time, not just its 'error' event - the outer spawnSync timeout catches a leaked inner timer.
// Measures the child's actual exit time, not just its 'error' event.
// The outer spawnSync timeout catches a leaked inner timer.

const bugStallMs = common.platformTimeout(10000);
const outerTimeoutMs = common.platformTimeout(2000);

const child = spawnSync(process.execPath, ['-e', `

@aduh95 aduh95 Aug 24, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const child = spawnSync(process.execPath, ['-e', `
spawnSyncAndExitWithoutError(process.execPath, ['-e', `

Signed-off-by: kishore280 <maheshwarankishore@gmail.com>
@codecov

codecov Bot commented Aug 24, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 90.16%. Comparing base (0b89f8f) to head (7c6b37f).
⚠️ Report is 21 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #65506      +/-   ##
==========================================
+ Coverage   90.14%   90.16%   +0.02%     
==========================================
  Files         751      751              
  Lines      252697   253586     +889     
  Branches    47557    47772     +215     
==========================================
+ Hits       227788   228648     +860     
- Misses      16181    16200      +19     
- Partials     8728     8738      +10     
Files with missing lines Coverage Δ
lib/child_process.js 94.12% <100.00%> (+<0.01%) ⬆️

... and 50 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

child_process Issues and PRs related to the child_process subsystem. needs-ci PRs that need a full CI run.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

child_process: timeout option never clears on spawn-time failure (ENOENT etc), hangs process for full timeoutMs

6 participants