如何在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 =产生的产卵函数
  • 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(child_process.js:975:11)处产生ENOENT
  • 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无法找到可执行文件来解决问题。

第一步:确保spawn是正确的方式

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

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

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

{ cwd: undefined, env: process.env }

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

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

步骤2:识别发出错误事件的事件发射器

搜索你的源代码中的每个调用spawn ,或child_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

有两种可能的情况:

  1. 你依靠默认的spawn行为,所以子进程环境将和process.env
  2. 你明确地传递一个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:确保在PATH定义的目录中存在command

如果文件名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

Windows解决方案:用节点交叉产卵替换产卵 。 例如像你的app.js的开始:

 (function() { var childProcess = require("child_process"); childProcess.spawn = require('cross-spawn'); })(); 

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

对于任何可能偶然发现的人来说,如果所有其他的答案都不能帮助你,并且你在Windows上,那么知道在Windows上spawn一个大问题,并且PATHEXT环境变量会导致某些调用产生不能工作关于如何安装目标命令。

@ laconbass的答案帮助了我,可能是最正确的。

我来到这里是因为我错误地使用了spawn。 举一个简单的例子:

这是不正确的:

  const s = cp.spawn('npm install -D suman', [], { cwd: root }); 

这是不正确的:

  const s = cp.spawn('npm', ['install -D suman'], { cwd: root }); 

这是对的:

  const s = cp.spawn('npm', ['install','-D','suman'], { cwd: root }); 

在我的情况下,由于没有安装必要的依赖系统资源,我得到此错误。

更具体地说,我有一个使用ImageMagick的NodeJS应用程序。 尽管安装了npm软件包,但未安装核心Linux ImageMagick。 我做了一个apt-get来安装ImageMagick,之后所有的工作都很好!

对于Windows上的ENOENT, https://github.com/nodejs/node-v0.x-archive/issues/2318#issuecomment-249355505修复它。;

例如将spawn('npm',['-v'],{stdio:'inherit'})替换为:

  • 对于所有的node.js版本:

     spawn(/^win/.test(process.platform) ? 'npm.cmd' : 'npm', ['-v'], {stdio: 'inherit'}) 
  • 对于node.js 5.x和更高版本:

     spawn('npm', ['-v'], {stdio: 'inherit', shell: true}) 

我遇到了同样的问题,但我找到了一个简单的方法来解决它。 如果程序已被用户添加到PATH(例如正常的系统命令工作),它似乎是spawn()错误。

要解决这个问题,你可以使用哪个模块( npm install --save which ):

 // Require which and child_process const which = require('which'); const spawn = require('child_process').spawn; // Find npm in PATH const npm = which.sync('npm'); // Execute const noErrorSpawn = spawn(npm, ['install']); 

如果不是节点模块,请确保要执行的模块已安装或完整路径

我试图在Debian Linux系统上的VS Code编辑器中调试node.js程序时出现这个错误。 我注意到在Windows上同样的事情工作正常。 之前给出的解决方案没有太多的帮助,因为我没有写任何“spawn”命令。 有问题的代码大概是由微软写的,隐藏在VS Code程序的底层。

接下来我注意到,node.js在Windows上被称为node,但在Debian上(大概是在基于Debian的系统上,比如Ubuntu),它被称为nodejs。 所以我创建了一个别名 – 从一个根终端,我跑了

ln -s / usr / bin / nodejs / usr / local / bin / node

这解决了这个问题。 在其他情况下,相同或相似的过程可能会起作用,其他情况下,您的node.js被称为nodejs,但是您正在运行一个程序,期望它被称为节点,反之亦然。

我得到了Windows 8相同的错误。问题是因为您的系统路径的环境变量是缺少的。 将“C:\ Windows \ System32 \”值添加到您的系统PATH变量。

使用require('child_process').exec而不是产生一个更具体的错误信息!

例如:

 var exec = require('child_process').exec; var commandStr = 'java -jar something.jar'; exec(commandStr, function(error, stdout, stderr) { if(error || stderr) console.log(error || stderr); else console.log(stdout); }); 

如果你在Windows上,Node.js在处理报价时会做一些有趣的事情,这些报价可能导致你发出一个你知道在控制台上工作的命令,但是在Node中运行的命令不会。 例如以下应该工作:

 spawn('ping', ['"8.8.8.8"'], {}); 

但失败。 有一个很windowsVerbatimArguments没有记录的选项windowsVerbatimArguments用于处理引用/类似的似乎做的伎俩,只要确保将以下添加到您的opts对象:

 const opts = { windowsVerbatimArguments: true }; 

你的命令应该恢复正常。

  spawn('ping', ['"8.8.8.8"'], { windowsVerbatimArguments: true }); 

C:\Windows\System32\path环境变量。

脚步

  1. 转到我的电脑和属性

  2. 点击高级设置

  3. 然后在环境变量上

  4. 选择Path ,然后点击编辑

  5. 粘贴以下(如果尚不存在): C:\Windows\System32\

  6. 关闭命令提示符

  7. 运行你想运行的命令

Windows 8环境变量截图