How do I debug "Error: spawn ENOENT" on node.js?

When I get the following error:

events.js:72
        throw er; // Unhandled 'error' event
              ^
Error: spawn ENOENT
    at errnoException (child_process.js:1000:11)
    at Process.ChildProcess._handle.onexit (child_process.js:791:34)

What procedure can I follow to fix it?

Author note : Lots of issues with this error encouraged me to post this question for future references.

Related questions:

  • using spawn function with NODE_ENV=production
  • node.js child_process.spawn ENOENT error - only under supervisord
  • spawn ENOENT node.js error
  • https://stackoverflow.com/questions/27603713/nodejs-spawn-enoent-error-on-travis-calling-global-npm-package
  • Node JS - child_process spawn('npm install') in Grunt task results in ENOENT error
  • Running "foreman" task Fatal error: spawn ENOENT
  • unhandled error event in node js Error: spawn ENOENT at errnoException (child_process.js:975:11)
  • Node.js SpookyJS: error executing hello.js
  • https://stackoverflow.com/questions/26572214/run-grunt-on-a-directory-nodewebkit
  • Run exe file with Child Process NodeJS
  • Node: child_process.spawn not working on Java even though it's in the path (ENOENT)
  • spawn ENOENT error with NodeJS (PYTHON related)
  • image resizing is not working in node.js (partial.js) (non-installed dependency)
  • npm install error ENOENT (build dependency problem)
  • Cannot install node.js - oracle module on Windows 7 (build dependency problem)
  • Error installing gulp using nodejs on windows (strange case)

  • I found a particular easy way to get the idea of the root cause of:

    Error: spawn ENOENT
    

    The problem of this error is, there is really little information in the error message to tell you where the call site is, ie which executable/command is not found, especially when you have a large code base where there are a lot of spawn calls. On the other hand, if we know the exact command that cause the error then we can follow @laconbass' answer to fix the problem.

    I found a very easy way to spot which command cause the problem rather than adding event listeners everywhere in your code as suggested in @laconbass' answer. The key idea is to wrap the original spawn call with a wrapper which prints the arguments send to the spawn call.

    Here is the wrapper function, put it at the top of the index.js or whatever your server's starting script.

    (function() {
        var childProcess = require("child_process");
        var oldSpawn = childProcess.spawn;
        function mySpawn() {
            console.log('spawn called');
            console.log(arguments);
            var result = oldSpawn.apply(this, arguments);
            return result;
        }
        childProcess.spawn = mySpawn;
    })();
    

    Then the next time you run your application, before the uncaught exception's message you will see something like that:

    spawn called
    { '0': 'hg',
      '1': [],
      '2':
       { cwd: '/* omitted */',
         env: { IP: '0.0.0.0' },
         args: [] } }
    

    In this way you can easily know which command actually is executed and then you can find out why nodejs cannot find the executable to fix the problem.


    Step 1: Ensure spawn is called the right way

    First, review the docs for child_process.spawn( command, args, options ):

    Launches a new process with the given command , with command line arguments in args . If omitted, args defaults to an empty Array.

    The third argument is used to specify additional options, which defaults to:

    { cwd: undefined, env: process.env }

    Use env to specify environment variables that will be visible to the new process, the default is process.env .

    Ensure you are not putting any command line arguments in command and the whole spawn call is valid . Proceed to next step.

    Step 2: Identify the Event Emitter that emits the error event

    Search on your source code for each call to spawn , or child_process.spawn , ie

    spawn('some-command', [ '--help' ]);
    

    and attach there an event listener for the 'error' event, so you get noticed the exact Event Emitter that is throwing it as 'Unhandled'. After debugging, that handler can be removed.

    spawn('some-command', [ '--help' ])
      .on('error', function( err ){ throw err })
    ;
    

    Execute and you should get the file path and line number where your 'error' listener was registered. Something like:

    /file/that/registers/the/error/listener.js:29
          throw err;
                ^
    Error: spawn ENOENT
        at errnoException (child_process.js:1000:11)
        at Process.ChildProcess._handle.onexit (child_process.js:791:34)
    

    If the first two lines are still

    events.js:72
            throw er; // Unhandled 'error' event
    

    do this step again until they are not. You must identify the listener that emits the error before going on next step.

    Step 3: Ensure the environment variable $PATH is set

    There are two possible scenarios:

  • You rely on the default spawn behaviour, so child process environment will be the same as process.env .
  • You are explicity passing an env object to spawn on the options argument.
  • In both scenarios, you must inspect the PATH key on the environment object that the spawned child process will use.

    Example for scenario 1

    // inspect the PATH key on process.env
    console.log( process.env.PATH );
    spawn('some-command', ['--help']);
    

    Example for scenario 2

    var env = getEnvKeyValuePairsSomeHow();
    // inspect the PATH key on the env object
    console.log( env.PATH );
    spawn('some-command', ['--help'], { env: env });
    

    The absence of PATH (ie, it's undefined ) will cause spawn to emit the ENOENT error , as it will not be possible to locate any command unless it's an absolute path to the executable file.

    When PATH is correctly set, proceed to next step. It should be a directory, or a list of directories. Last case is the usual.

    Step 4: Ensure command exists on a directory of those defined in PATH

    Spawn may emit the ENOENT error if the filename command (ie, 'some-command') does not exist in at least one of the directories defined on PATH .

    Locate the exact place of command . On most linux distributions, this can be done from a terminal with the which command. It will tell you the absolute path to the executable file (like above), or tell if it's not found.

    Example usage of which and its output when a command is found

    > which some-command
    some-command is /usr/bin/some-command
    

    Example usage of which and its output when a command is not found

    > which some-command
    bash: type: some-command: not found
    

    miss-installed programs are the most common cause for a not found command. Refer to each command documentation if needed and install it.

    When command is a simple script file ensure it's accessible from a directory on the PATH . If it's not, either move it to one or make a link to it.

    Once you determine PATH is correctly set and command is accessible from it, you should be able to spawn your child process without spawn ENOENT being thrown.


    正如@DanielImfeld指出的那样,如果在选项中指定“cwd”,ENOENT将被抛出,但给定的目录不存在。

    链接地址: http://www.djcxy.com/p/65828.html

    上一篇: 我如何使用全局路径运行grunt?

    下一篇: 如何在node.js上调试“错误:产生ENOENT”?