Skip to content

child_process.exec(...) (and fork, spawn) do not abort with expected signal.reason #47814

Closed
@MadLittleMods

Description

@MadLittleMods

Version

v18.16.0

Platform

Microsoft Windows NT 10.0.19044.0 x64

Subsystem

No response

What steps will reproduce the bug?

  1. Use Node.js v18.16.0
  2. Run this script in the REPL or save as a script and run with Node.js
    (async () => {
        const { spawn } = require('child_process');
    
        const abortController = new AbortController();
        setTimeout(() => {
            abortController.abort(new Error('My custom error'));
        }, 0);
    
        try {
            await new Promise((resolve, reject) => {
                const child = spawn('echo', ["foo"], { signal: abortController.signal });
                child.on('error', (err) => {
                    reject(err);
                });
                child.on('close', () => {
                    resolve();
                });
            });
        } catch(err) {
            console.log('err', err);
            // err AbortError: The operation was aborted
            //     at abortChildProcess (node:child_process:720:27)
            //     at EventTarget.onAbortListener (node:child_process:790:7)
            //     at [nodejs.internal.kHybridDispatch] (node:internal/event_target:737:20)
            //     at EventTarget.dispatchEvent (node:internal/event_target:679:26)
            //     at abortSignal (node:internal/abort_controller:314:10)
            //     at AbortController.abort (node:internal/abort_controller:344:5)
            //     at Timeout._onTimeout (REPL22:6:25)
            //     at listOnTimeout (node:internal/timers:569:17)
            //     at process.processTimers (node:internal/timers:512:7) {
            //   code: 'ABORT_ERR'
        }
    })();
  3. Notice AbortError: The operation was aborted instead of our custom signal.reason -> Error: My custom error

How often does it reproduce? Is there a required condition?

Consistently reproducible (always)

What is the expected behavior? Why is that the expected behavior?

I expect this to behave like the fetch API where the error thrown is the signal.reason that we aborted with. Example:

(async () => {
    const abortController = new AbortController();
    setTimeout(() => {
        abortController.abort(new Error('My custom error'));
    }, 0);

    try {
        const res = await fetch('https://nodejs.org/', { signal: abortController.signal });
    } catch(err) {
        console.log('err', err);
        // err Error: My custom error
        //     at Object.fetch (node:internal/deps/undici/undici:11457:11)
        //     at async REPL17:8:21
    }
})();

What do you see instead?

It always throws: AbortError: The operation was aborted

Additional information

Related to #43874

Metadata

Metadata

Assignees

No one assigned

    Labels

    abortcontrollerIssues and PRs related to the AbortController APIchild_processIssues and PRs related to the child_process subsystem.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions