Skip to content

spawn EAGAIN produces a sequence of uncaught exceptions that cannot be handled Β #32943

@ggoodman

Description

@ggoodman
  • Version: 12.16.1
  • Platform: Linux eb68db941f4a 5.3.0-1016-aws #17~18.04.1-Ubuntu SMP Fri Mar 27 20:11:52 UTC 2020 x86_64 GNU/Linux
  • Subsystem: child_process

What steps will reproduce the bug?

Produced by code that looks like this:

    this.process = spawn(this.command, this.commandArgs, {
      env: this.env,
    });

    this.process.once('exit', this.onProcessExit);
    this.process.stdout.on('data', this.onProcessStdOut);
    this.process.stderr.on('data', this.onProcessStdErr);
  1. In an async function, we call child_process.spawn().
  2. process.on('uncaughtException') gets triggered with an EGAIN on the attempt to spawn the child process. The stack for this uncaught exception looks like [1]. Note that while the triggering condition was in an async function, it was not converted into a promise rejection as I would have expected. The fact that the following exceptions were reported after, despite having synchronous call-stacks back to our call to spawn makes me think this is happening outside JavaScript-land.
  3. Next, we get two identical uncaught exceptions, having a stack originating at our code calling spawn [2]. I suspect these are for stdout / stderr, respectively.

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

This was produced within a docker container on an ~80% loaded host with several hundred identical containers in operation.

What is the expected behavior?

EAGAIN exceptions thrown by spawn should be handle-able by user-space code and should not produce uncaught exceptions outside normal control flow.

What do you see instead?

As described above, what appears to be an un-handleable exception thrown outside normal control flow.

Additional information

Stack traces:

1:

uncaught exception Error: spawn /usr/local/bin/node EAGAIN
    at Process.ChildProcess._handle.onexit (internal/child_process.js:267:19)
    at onErrorNT (internal/child_process.js:469:16)
    at processTicksAndRejections (internal/process/task_queues.js:84:21)

2:

uncaught exception Error: read ENOTCONN
    at tryReadStart (net.js:567:20)
    at Socket._read (net.js:578:5)
    at Socket.Readable.read (_stream_readable.js:478:10)
    at Socket.read (net.js:618:39)
    at new Socket (net.js:372:12)
    at Object.Socket (net.js:263:41)
    at createSocket (internal/child_process.js:314:14)
    at ChildProcess.spawn (internal/child_process.js:437:23)
    at spawn (child_process.js:548:9)
    at SandboxRuntime.spawn (/path/to/out/call/to/spawn.js:123:45)

I also note this comment that makes me suspect the libuv / node-core boundary: #21203 (comment)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions