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

时间:2014-12-29 12:22:01

标签: node.js debugging error-handling child-process spawn

27 个答案:

答案 0 :(得分:194)

我找到了一种特别简单的方法来了解根本原因:

Error: spawn ENOENT

此错误的问题是,错误消息中几乎没有信息告诉您调用站点在哪里,即找不到哪个可执行文件/命令,尤其是当您有大量代码库时产卵电话。另一方面,如果我们知道导致错误的确切命令,那么我们可以按@laconbass' answer来解决问题。

我找到了一种非常简单的方法来发现哪个命令导致问题,而不是像@ 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 :(得分:99)

第1步:确保以正确方式调用spawn

首先,查看docs for 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

有两种可能的情况:

  1. 您依赖于默认的spawn行为,因此子流程环境将与process.env相同。
  2. 您明确地在env参数上将spawn对象传递给options
  3. 在这两种情况下,您都必须检查生成的子进程将使用的环境对象上的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

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

    找到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的情况下生成您的子进程。

答案 2 :(得分:29)

作为@DanielImfeld pointed it,如果您指定" cwd"将会抛出ENOENT。在选项中,但给定的目录不存在。

答案 3 :(得分:24)

Windows解决方案:将spawn替换为node-cross-spawn。例如,在app.js的开头就是这样:

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

答案 4 :(得分:22)

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

但是,我建议这样做:

const s = cp.spawn('bash');
s.stdin.end(`cd "${root}" && npm install -D suman`);
s.once('exit', code => {
   // exit
});

这是因为只要安装了bash,cp.on('exit', fn)事件就会一直触发,否则,cp.on('error', fn)事件可能会先触发,如果我们以第一种方式使用它,如果我们启动& #39; NPM'直。

答案 5 :(得分:19)

在Windows中,只需添加shell: true选项即可解决我的问题:

不正确:

const { spawn } = require('child_process');
const child = spawn('dir');

正确:

const { spawn } = require('child_process');
const child = spawn('dir', [], {shell: true});

答案 6 :(得分:16)

对于可能偶然发现此问题的任何人,如果所有其他答案都没有帮助且您在Windows上,请知道当前有a big issue with spawn on WindowsPATHEXT环境变量可能会导致某些调用根据目标命令的安装方式,spawn不起作用。

答案 7 :(得分:16)

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

e.g。用以下内容替换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})
    

答案 8 :(得分:6)

如何研究引发错误的生成调用:

已知的常见原因

  1. 环境问题

    • 命令可执行文件在系统中不存在(未安装依赖项)。 请参见prominc's answer
    • 该命令可执行文件在PATH环境变量指定的目录中不存在。
  2. 仅限Windows的错误/怪胎

  3. 使用错误的spawn('command', ['--argument', 'list'], { cwd, env, ...opts })

    • 指定的工作目录(opts.cwd)不存在·请参见leeroy-brun's answer
    • 命令String中的参数列表 spawn('command --wrong --argument list')
    • 在命令字符串 spawn('ENV_VAR=WRONG command')
    • 中包含环境变量
    • 参数列表Array指定为String spawn('cmd', '--argument list')
    • 未设置PATH环境变量 spawn('cmd', [], { env: { variable } } => spawn('cmd', [], { env: { ...process.env, variable } }

ENOENT有2个可能的起源:

  1. 您正在编写的代码
  2. 您依赖的代码

当来源是您所依赖的代码时,通常的原因是环境问题(或Windows怪癖)


答案 9 :(得分:6)

就我而言,由于未安装必要的相关系统资源,我引发了此错误。

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

答案 10 :(得分:6)

在任何人花大量时间调试此问题之前,大多数时间可以通过删除node_modules并重新安装软件包来解决。

要安装:

如果存在锁定文件,则可以使用

yarn install --frozen-lockfile

npm ci

分别。如果没有,那么

yarn install

npm i

答案 11 :(得分:2)

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

要解决此问题,您可以使用which模块(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']);

答案 12 :(得分:1)

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

答案 13 :(得分:0)

最近我也遇到了类似的问题。

Starting the development server...

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

Error: spawn null ENOENT
    at Process.ChildProcess._handle.onexit (internal/child_process.js:240:19)
    at onErrorNT (internal/child_process.js:415:16)
    at process._tickCallback (internal/process/next_tick.js:63:19)
Emitted 'error' event at:
    at Process.ChildProcess._handle.onexit (internal/child_process.js:246:12)
    at onErrorNT (internal/child_process.js:415:16)
    at process._tickCallback (internal/process/next_tick.js:63:19)
error Command failed with exit code 1.

这是因为 .envBROWSER 文件配置错误。我有 BROWSER=null,但它必须是 BROWSER=none。更改该配置解决了我的问题。

答案 14 :(得分:0)

在我要删除的节点中,删除所有AppData / Roaming / npm和AppData / Roaming / npm-cache并重新安装节点即可解决此问题。

答案 15 :(得分:0)

使用require('child_process').exec代替spawn以获取更具体的错误消息!

例如:

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

答案 16 :(得分:0)

尽管对于某些人来说,这可能是环境问题或另一个问题,但我刚刚在Windows 10上安装了Visual Studio Code的Latex Workshop扩展,并在尝试构建/预览PDF时看到此错误。以管理员身份运行VS Code为我解决了这个问题。

答案 17 :(得分:0)

如果您无法修改其源的应用程序遇到此问题,请考虑使用环境变量#include <iostream> using namespace std; int main() { bool empty_bool; char empty_char; int empty_int; float empty_float; double empty_double; cout << "Please enter a value for all inbuilt primitive types in C++" << endl; cout << "Boolean:"; cin >> empty_bool; cout << "Char"; cin >> empty_char; cout << "Int"; cin >> empty_int; cout << "float"; cin >> empty_float; cout << "double"; cin >> empty_double; } 设置为NODE_DEBUG来调用它,例如child_process。这将为您提供在哪个目录中调用了哪些命令行的信息,通常最后一个详细信息是失败的原因。

答案 18 :(得分:0)

您要更改env选项吗?

然后看看这个答案。


我正在尝试生成一个节点进程和TIL,以便在生成时应散布现有的环境变量,否则您将失去PATH环境变量以及其他重要变量。

这是我的解决方法:

const nodeProcess = spawn('node', ['--help'], {
  env: {
    // by default, spawn uses `process.env` for the value of `env`
    // you can _add_ to this behavior, by spreading `process.env`
    ...process.env,
    OTHER_ENV_VARIABLE: 'test',
  }
});

答案 19 :(得分:0)

我在Windows上遇到了这个问题,其中使用完全相同的命令(省略参数)调用execspawn对于exec可以正常工作(所以我知道我的命令在{ {1}}),但$PATH会给出ENOENT。原来,我只需要在正在使用的命令后附加spawn

.exe

答案 20 :(得分:0)

我的情况下的解决方案

var spawn = require('child_process').spawn;

const isWindows = /^win/.test(process.platform); 

spawn(isWindows ? 'twitter-proxy.cmd' : 'twitter-proxy');
spawn(isWindows ? 'http-server.cmd' : 'http-server');

答案 21 :(得分:0)

在运行我的测试用例时,我也遇到了这个恼人的问题,所以我尝试了很多方法来解决它。但对我有用的方法是从包含主文件的目录运行你的测试运行器,其中包括你的 nodejs spawn 函数:

nodeProcess = spawn('node',params, {cwd: '../../node/', detached: true });

例如,此文件名为test.js ,因此只需移至包含它的文件夹。就我而言,它是这样的测试文件夹:

cd root/test/

然后从运行你的测试运行器在我的情况下它的摩卡,所以它将是这样的:

mocha test.js

我浪费了一天以上的时间来弄清楚这一点。享受!!

答案 22 :(得分:0)

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

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

但失败了。有一个奇妙的未记录的选项windowsVerbatimArguments用于处理引号/类似似乎可以解决问题,只需确保将以下内容添加到您的opts对象中:

const opts = {
    windowsVerbatimArguments: true
};

你的命令应该重新开始。

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

答案 23 :(得分:0)

我在Windows 8中遇到了同样的错误。问题是由于缺少系统路径的环境变量。将“C:\ Windows \ System32 \”值添加到系统PATH变量。

答案 24 :(得分:0)

尝试从Debian Linux系统上的VS Code编辑器中调试node.js程序时出现此错误。我注意到在Windows上同样的功能正常。之前给出的解决方案没有多大帮助,因为我没有写任何&#34; spawn&#34;命令。违规代码大概是由Microsoft编写的,隐藏在VS Code程序的引擎盖下。

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

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

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

答案 25 :(得分:-1)

C:\Windows\System32\添加到path环境变量。

步骤

  1. 转到我的计算机和媒体资源

  2. 点击高级设置

  3. 然后在环境变量

  4. 选择Path,然后点击修改

  5. 如果不存在,请粘贴以下内容:C:\Windows\System32\

  6. 关闭命令提示符

  7. 运行您要运行的命令

  8. Windows 8 Environment variables screenshot

答案 26 :(得分:-1)

尝试了一切都没有用,我的系统有不同的问题。

对我来说可行的解决方案是 运行命令: npm config set script-shell "C:\Program Files\git\bin\bash.exe"