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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/27688804/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 18:15:30  来源:igfitidea点击:

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

node.jsdebuggingerror-handlingchild-processspawn

提问by laconbass

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:

相关问题:

采纳答案by Jiaji Zhou

NOTE: This error is almost always caused because the command does not exist, because the working directory does not exist, or from a windows-only bug.

注意:此错误几乎总是由于命令不存在、工作目录不存在或仅 Windows 的错误引起的。

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, i.e. 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' answerto fix the problem.

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

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.

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

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

这是包装函数,把它放在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;
})();

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.

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

回答by laconbass

Step 1: Ensure spawnis called the right way

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

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

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

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

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

{ cwd: undefined, env: process.env }

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

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

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

{ cwd: undefined, env: process.env }

使用env指定的环境变量,这将是新的过程可见,默认为process.env

Ensure you are not putting any command line arguments in commandand the whole spawncall is valid. Proceed to next step.

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

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

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

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

在每次调用spawn, or 时搜索您的源代码child_process.spawn,即

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 $PATHis set

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

There are two possible scenarios:

有两种可能的情况:

  1. You rely on the default spawnbehaviour, so child process environment will be the same as process.env.
  2. You are explicity passing an envobject to spawnon the optionsargument.
  1. 您依赖于默认spawn行为,因此子进程环境将与process.env.
  2. 你是明确地传递一个env对象spawnoptions参数。

In both scenarios, you must inspect the PATHkey on the environment object that the spawned child process will use.

在这两种情况下,您都必须检查PATH生成的子进程将使用的环境对象上的键。

Example for scenario 1

场景 1 的示例

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

Example for scenario 2

场景 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(i.e., it's undefined) will cause spawnto emit the ENOENTerror, as it will not be possible to locate any commandunless it's an absolute path to the executable file.

不存在PATH(即它的undefined)将导致spawn发出ENOENT错误,因为command除非它是可执行文件的绝对路径,否则无法定位任何。

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

如果PATH设置正确,进行下一步。它应该是一个目录或目录列表。最后一种情况是常见的。

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

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

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

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

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

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

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

找到命令时 which 及其输出的示例用法

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

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

找不到命令时 which 及其输出的示例用法

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

miss-installed programs are the most common cause for a not foundcommand.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.

当 command 是一个简单的脚本文件时,确保它可以从PATH. 如果不是,请将其移至其中一个或建立指向它的链接。

Once you determine PATHis correctly set and commandis accessible from it, you should be able to spawn your child process without spawn ENOENTbeing thrown.

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

回答by Leeroy Brun

As @DanielImfeld pointed it, ENOENT will be thrown if you specify "cwd" in the options, but the given directory does not exist.

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

回答by Nilzor

Windows solution: Replace spawnwith node-cross-spawn. For instance like this at the beginning of your app.js:

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

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

回答by Alexander Mills

@laconbass's answer helped me and is probably most correct.

@laconbass 的回答对我有帮助,而且可能是最正确的。

I came here because I was using spawn incorrectly. As a simple example:

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

this is incorrect:

这是不正确的:

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

this is incorrect:

这是不正确的:

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

this is correct:

这是对的:

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

however, I recommend doing it this way:

但是,我建议这样做:

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

this is because then the cp.on('exit', fn)event will always fire, as long as bash is installed, otherwise, the cp.on('error', fn)event might fire first, if we use it the first way, if we launch 'npm' directly.

这是因为cp.on('exit', fn)只要安装了 bash,事件就会始终触发,否则cp.on('error', fn),如果我们使用第一种方式,如果我们直接启动“npm” ,事件可能会首先触发。

回答by Li Zheng

For ENOENT on Windows, https://github.com/nodejs/node-v0.x-archive/issues/2318#issuecomment-249355505fix it.

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

e.g. replace spawn('npm', ['-v'], {stdio: 'inherit'}) with:

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

  • for all node.js version:

    spawn(/^win/.test(process.platform) ? 'npm.cmd' : 'npm', ['-v'], {stdio: 'inherit'})
    
  • for node.js 5.x and later:

    spawn('npm', ['-v'], {stdio: 'inherit', shell: true})
    
  • 对于所有 node.js 版本:

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

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

回答by Alex Turpin

For anyone who might stumble upon this, if all the other answers do not help and you are on Windows, know that there is currently a big issue with spawnon Windowsand the PATHEXTenvironment variable that can cause certain calls to spawn to not work depending on how the target command is installed.

对于任何人谁可能在此跌倒,如果所有其他的答案没有帮助,你是在Windows上,知道的是,目前的一个大问题与spawn在WindowsPATHEXT环境变量,可能会导致某些呼叫产卵不工作,这取决于如何目标命令已安装。

回答by PromInc

In my case, I was getting this error thrown due to the necessary dependent system resources not being installed.

就我而言,由于没有安装必要的依赖系统资源,我抛出了这个错误。

More specifically, I have a NodeJS app that is utilizing ImageMagick. Despite having the npm package installed, the core Linux ImageMagick was not installed. I did an apt-get to install ImageMagick and after that all worked great!

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

回答by Rico Kahler

Are you changing the envoption?

你在改变env选项吗?

Then look at this answer.

然后看看这个答案。



I was trying to spawn a node process and TIL that you should spread the existing environment variables when you spawn else you'll loose the PATHenvironment variable and possibly other important ones.

我试图生成一个节点进程和 TIL,你应该在生成时传播现有的环境变量,否则你会丢失PATH环境变量和其他可能的重要变量。

This was the fix for me:

这对我来说是修复:

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

回答by ashkan nasirzadeh

in windows, simply adding shell: trueoption solved my problem:

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

incorrect:

不正确:

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

correct:

正确的:

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