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

当我收到以下错误:

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)

我可以按照什么程序来修复它?

作者注意 :许多与此错误有关的问题鼓励我发布此问题以供将来参考。

相关问题:

  • 使用带有NODE_ENV =生产的spawn函数
  • node.js child_process.spawn ENOENT错误 - 仅在supervisord下
  • 产生ENOENT node.js错误
  • https://stackoverflow.com/questions/27603713/nodejs-spawn-enoent-error-on-travis-calling-global-npm-package
  • 在Grunt任务中的节点JS - child_process spawn('npm install')导致ENOENT错误
  • 运行“工头”任务致命错误:产生ENOENT
  • 节点js中未处理的错误事件错误:在errnoException处产生ENOENT(child_process.js:975:11)
  • Node.js SpookyJS:执行hello.js时出错
  • https://stackoverflow.com/questions/26572214/run-grunt-on-a-directory-nodewebkit
  • 使用Child Process NodeJS运行exe文件
  • Node:child_process.spawn即使在路径中也不能在Java上工作(ENOENT)
  • 用NodeJS产生ENOENT错误(与PYTHON相关)
  • 图像大小调整在node.js(partial.js)中无效(未安装的依赖项)
  • npm安装错误ENOENT(构建依赖问题)
  • 无法在Windows 7上安装node.js - oracle模块(构建依赖关系问题)
  • 在windows上使用nodejs安装gulp时出错(奇怪的情况)

  • 我发现了一个特别简单的方法来获得以下根本原因的想法:

    Error: spawn ENOENT
    

    这个错误的问题是,错误消息中的确实很少的信息告诉你呼叫站点在哪里,即没有找到哪个可执行文件/命令,特别是当你有一个大的代码库时,有很多spawn调用。 另一方面,如果我们知道导致错误的确切命令,那么我们可以按照@laconbass的答案来解决问题。

    我发现了一个非常简单的方法来找出哪个命令导致问题,而不是像在@laconbass的回答中所建议的那样在代码中的任何地方添加事件监听器。 关键的想法是用一个打包发送给spawn调用的参数的包装器来包装原始的spawn调用。

    这里是包装函数,把它放在index.js的顶部或者你的服务器的启动脚本。

    (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;
    })();
    

    然后下一次运行应用程序时,在未捕获异常的消息之前,您会看到如下所示的内容:

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

    通过这种方式,您可以轻松地知道实际执行了哪个命令,然后您可以找出为什么nodejs无法找到可执行文件来解决问题。


    第1步:确保spawn被称为正确的方式

    首先,查看child_process.spawn(command,args,options)的文档:

    使用给定的command启动一个新进程,在args带有命令行参数。 如果省略, args默认为空数组。

    第三个参数用于指定其他选项,默认为:

    { cwd: undefined, env: process.env }

    使用env指定新进程可见的环境变量,缺省值为process.env

    确保你没有在command任何命令行参数,并且整个spawn调用是有效的 。 继续下一步。

    步骤2:确定发出错误事件的事件发射器

    在源代码中搜索每次调用spawnchild_process.spawn ,即

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

    并在那里附加一个事件监听器来处理'错误'事件,所以你会注意到将它抛出为'未处理'的确切的事件发射器。 调试后,该处理程序可以被删除。

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

    执行,你应该得到你的'错误'侦听器注册的文件路径和行号。 就像是:

    /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)
    

    如果前两行仍然存在

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

    再次做这一步,直到他们没有。 在继续下一步之前,您必须识别发出错误的侦听器。

    第3步:确保设置了环境变量$PATH

    有两种可能的情况:

  • 你依靠默认的spawn行为,所以子进程环境将与process.env相同。
  • 你明确地传递一个env对象来spawn options参数。
  • 在这两种情况下,您都必须检查生成的子进程将使用的环境对象上的PATH键。

    方案1的示例

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

    方案2的示例

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

    没有PATH (即undefined )会导致spawn发出ENOENT错误 ,因为除非它是可执行文件的绝对路径,否则将无法找到任何command

    当正确设置PATH ,继续下一步。 它应该是一个目录或一个目录列表。 最后一种情况是平常的。

    步骤4:确保command存在于PATH定义的目录中

    如果文件名command (即'some-command')在PATH定义的至少一个目录中不存在,则Spawn可能会发出ENOENT错误。

    找到command的确切位置。 在大多数Linux发行版中,这可以通过使用which命令从终端完成。 它会告诉你可执行文件的绝对路径(如上所述),或者告诉你是否找不到它。

    找到命令时使用哪一个及其输出的示例

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

    没有找到命令时使用哪个命令及其输出的示例

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

    未安装程序是找不到命令的最常见原因。 如有需要,请参阅每个命令文档并进行安装。

    当命令是简单的脚本文件时,请确保它可以从PATH上的目录访问。 如果不是,则将其移动到一个或建立一个链接。

    一旦你确定PATH被正确设置并且command可以从其中访问,你应该能够产生你的子进程而不会抛出子spawn ENOENT


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

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

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

    下一篇: How to make Grunt Deploy use global NPM modules instead of local ones