本文翻译自:How do I debug “Error: spawn ENOENT” on node.js?
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)
Author note : Lots of issues with this error encouraged me to post this question for future references. 作者注意 :许多与此错误有关的问题鼓励我发布此问题以供将来参考。
Related questions: 相关问题:
参考:https://stackoom.com/question/1sB7c/如何在node-js上调试-错误-生成ENOENT
spawn
is 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 inargs
. 使用给定command
启动新进程,并在args
使用命令行参数。 If omitted,args
defaults to an empty Array. 如果省略,则args
默认为空数组。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 isprocess.env
. 使用env
指定对新进程可见的环境变量,默认值为process.env
。
Ensure you are not putting any command line arguments in command
and the whole spawn
call is valid . 确保您不会把任何命令行参数的command
,整个spawn
呼叫是有效的 。 Proceed to next step. 继续进行下一步。
Search on your source code for each call to spawn
, or child_process.spawn
, ie 在源代码中搜索对spawn
或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. 在继续下一步之前,您必须确定发出错误的侦听器。
$PATH
is set 步骤3:确保设置了环境变量$PATH
There are two possible scenarios: 有两种可能的方案:
spawn
behaviour, so child process environment will be the same as process.env
. 您依赖于默认的spawn
行为,因此子进程环境将与process.env
相同。 env
object to spawn
on the options
argument. 您明确地传递了一个env
对象以在options
参数上spawn
。 In both scenarios, you must inspect the PATH
key 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
(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. 缺少PATH
(即undefined
)将导致spawn
发出ENOENT
错误 ,因为除非它是可执行文件的绝对路径,否则将无法定位任何command
。
When PATH
is correctly set, proceed to next step. 正确设置PATH
,请继续下一步。 It should be a directory, or a list of directories. 它应该是目录或目录列表。 Last case is the usual. 最后一种情况是通常的。
command
exists on a directory of those defined in PATH
步骤4:确保command
存在于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
. 如果在PATH
定义的至少一个目录中不存在文件名command
(即“ some-command”),则Spawn可能会发出ENOENT
错误。
Locate the exact place of command
. 找到确切的command
。 On most linux distributions, this can be done from a terminal with the which
command. 在大多数Linux发行版中,这可以从终端使用which
命令来完成。 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
. 当command是一个简单的脚本文件时,请确保可以从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. 一旦确定正确设置了PATH
并可以从中访问command
,您就应该能够生成子进程而不会抛出spawn ENOENT
。
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, 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. 另一方面,如果我们知道导致错误的确切命令,则可以按照@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. 我发现了一种非常简单的方法来找出导致该问题的命令,而不是像@laconbass的答案中所建议的那样在代码中的各处添加事件监听器。 The key idea is to wrap the original spawn call with a wrapper which prints the arguments send to the spawn call. 关键思想是使用包装器包装原始的spawn调用,该包装器将打印发送到spawn调用的参数。
Here is the wrapper function, put it at the top of the index.js
or 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无法找到可执行程序来解决该问题。
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. 更具体地说,我有一个使用ImageMagick的NodeJS应用程序。 Despite having the npm package installed, the core Linux ImageMagick was not installed. 尽管已安装了npm软件包,但尚未安装核心Linux ImageMagick。 I did an apt-get to install ImageMagick and after that all worked great! 我做了一个易于安装ImageMagick的工作,之后一切都变好了!
对于任何人谁可能偶然发现了这一点,如果所有其他的答案不帮助你,你是在Windows上,知道的是,目前有一个很大的问题, spawn
在Windows和PATHEXT
环境变量,可能会导致某些呼叫产卵到不行视关于如何安装目标命令。
Windows solution: Replace spawn
with node-cross-spawn . 的Windows解决方案:更换spawn
与节点交叉产卵 。 For instance like this at the beginning of your app.js: 例如在您的app.js开头这样的例子:
(function() {
var childProcess = require("child_process");
childProcess.spawn = require('cross-spawn');
})();