ChatGPT解决这个技术问题 Extra ChatGPT

如何在 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=production 的 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

Node JS - Grunt 任务中的 child_process spawn('npm install') 导致 ENOENT 错误

运行“工头”任务致命错误:spawn 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

使用子进程 NodeJS 运行 exe 文件

节点:child_process.spawn 无法在 Java 上运行,即使它在路径中(ENOENT)

使用 NodeJS 产生 ENOENT 错误(与 PYTHON 相关)

图像大小调整在 node.js (partial.js) 中不起作用(未安装的依赖项)

npm install error ENOENT(构建依赖问题)

无法在 Windows 7 上安装 node.js - oracle 模块(构建依赖问题)

在 Windows 上使用 nodejs 安装 gulp 时出错(奇怪的情况)

在我的例子中,我像使用 exec 一样将整个命令作为字符串传递,而不是将命令作为第一个参数传递,将选项作为第二个参数的数组传递。例如,我在做 spawn( "adb logcat -c" ) 而不是 spawn( "adb", [ "logcat", "-c" ] )

f
fuzzyTew

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

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

Error: spawn ENOENT

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


这是另一个想法:只需将 spawn() 更改为 exec() 并重试。 exec() 将告诉您它尝试运行什么命令。
重要提示:确保将上面的代码放置在尽可能靠近主 JS 文件的开头。如果您首先加载其他模块,它们可以隐藏“spawn”函数,并且永远不会调用这里的覆盖。
我没有运气使用脚本。它根本不起作用。
那么你将如何在 grunt 文件中使用这个方法呢?我不知道把这个放在哪里。
这对我来说非常有效。我只是把它放在我的 gulpfile.js 文件的顶部,然后 bingo bango bongo,生成日志!
M
Marcel Bro

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

首先,查看 docs for child_process.spawn( command, args, options )

使用给定的命令启动一个新进程,并在 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

有两种可能的情况:

您依赖默认生成行为,因此子进程环境将与 process.env 相同。您明确地传递了一个 env 对象以在 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 中定义的目录中

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

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

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

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

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

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

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

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

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


这对我调试 Spawn ENOENT 非常有帮助。我已经多次引用它。谢谢!
我还发现,如果您在选项中指定 cwd,则会抛出 ENOENT,但给定目录不存在。
@DanielImfeld 总救星。你应该写一个这样说的答案。
当您使用 spawn('some-command', ['--help'], { env: env });(如本答案中的第 3 步所示)并传递自定义环境时,请务必指定 PATH,例如:{ env: { PATH: process.env.PATH } }。默认情况下, env 选项不会从当前 env 继承变量。
我能够通过将 shell: true 传递给 spawn 选项来解决我的问题。
C
Community

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


那么有没有办法在特定目录中执行命令?
在 Windows (7) 中,您似乎还需要在 cwd 路径中包含驱动器号:'c:/...' 而不仅仅是 '/...'
T
TechDogLover OR kiaNasirzadeh

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

不正确:

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

正确的:

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

谢谢!这解决了我的问题,无需定义 cmd 或路径
添加 { shell: true } 也适用于 MacOS。
一天后终于解决了我的问题!在窗口外运行,这解决了它,非常感谢。
N
Nilzor

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

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

工作,除了它是一个插件,不需要 child_process。与节点的 spawn 或 spawnSync 完全相同,因此它是替代品。 var spawn = require('cross-spawn'); // Spawn NPM asynchronously var child = spawn('npm', ['list', '-g', '-depth', '0'], { stdio: 'inherit' });
L
Li Zheng

对于 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})


在哪里进行这些修改?
关键部分是添加 shell: true
A
Alexander Mills

@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) 事件就会始终触发,否则,如果我们以第一种方式使用它,如果我们直接启动“npm”,则可能会首先触发 cp.on('error', fn) 事件。


考虑重构我的答案以提供“一般指南”,并为问题的每个原因留下细节(错过依赖关系、不正确的调用、错误的环境......)。
喜欢这个答案的每个人都可能对这个原生替代方案感兴趣:gist.github.com/ORESoftware/7bf225f0045b4649de6848f1ea5def4c
否决,因为如果您想要的是一个外壳,那么您应该使用 child_process.exec 或将 shell: true 传递给 spawn
@givanse 不一定正确 - 您可能想要运行 zsh 或 bash 或 fsh ,具体取决于您要使用的 shell,并且行为也不同
A
Alex Turpin

对于任何可能偶然发现这一点的人,如果所有其他答案都没有帮助并且您在 Windows 上,请知道当前有 a big issue with spawn on WindowsPATHEXT 环境变量可能导致某些调用产生不工作,具体取决于如何目标命令已安装。


解决方案是什么?
使用 node-cross-spawn 对我有用。请参阅下面的答案:stackoverflow.com/a/35561971/507339
花了很长时间试图找出问题所在,这最终成为了问题。我放弃了 spawn,只使用了 exec
2
2 revs

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

使用 NODE_DEBUG=child_process,感谢 @karl-richter。简单,快速,2019 年 10 月

使用包装器来装饰 child_process.spawn,感谢 @jiaji-zhou。简单,快速,2015 年 1 月

漫长的过程,归功于@laconbass。复杂,时间成本,2014 年 12 月

已知的常见原因

环境问题 系统中不存在命令可执行文件(未安装依赖项)。请参阅 prominc 的答案命令可执行文件不存在于 PATH 环境变量指定的目录中。可执行二进制文件是使用不兼容的库编译的。请参阅 danilo-ramirez 回答仅 Windows 的错误/怪癖 '.cmd' 扩展名/外壳:是的。见李正回答管理员权限。见史蒂夫的回答 错误的 spawn('command', ['--argument', 'list'], { cwd, env, ...opts }) 用法 指定的工作目录 (opts.cwd) 不存在·见 leeroy-brun 的answer 命令字符串中的参数列表 spawn('command --wrong --argument list') 命令字符串中的环境变量 spawn('ENV_VAR=WRONG command') 参数列表 指定为字符串的数组 spawn('cmd', '--argument list ') 未设置 PATH 环境变量 spawn('cmd', [], { env: { variable } } => spawn('cmd', [], { env: { ...process.env, variable } }

ENOENT 有 2 个可能的来源: 您正在编写的代码 您所依赖的代码 当来源是您所依赖的代码时,通常原因是环境问题(或 Windows 怪癖)


我正在使用“ab”命令执行 execa,但容器中没有安装“Apache Bench”......所以,第一个“环境问题”案例......
P
PromInc

就我而言,由于未安装必要的依赖系统资源,我收到了这个错误。

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


Windows 是否也需要安装 ImageMagick?我在 Windows 上测试并出现错误
运行 yarn(安装)修复它
只需运行 brew install imagemagick
C
Community

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

安装:

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

yarn install --frozen-lockfile

或者

npm ci

分别。如果不是那么

yarn install

或者

npm i

哇,这么简单的解决方案,它对我有用!每个人都应该先尝试一下,看看它是否能解决问题。
R
Rico Kahler

您要更改 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',
  }
});

K
Kalle Richter

如果您在使用无法修改其源的应用程序时遇到此问题,请考虑在环境变量 NODE_DEBUG 设置为 child_process 的情况下调用它,例如 NODE_DEBUG=child_process yarn test。这将为您提供在哪个目录中调用了哪些命令行的信息,通常最后一个细节是失败的原因。


您知道能够使用此技术的最小节点 --version 吗?
@laconbass 不。我认为这是一个很好的 SO 问题,将在数小时内得到答复。
只是好奇。这比我检查为接受的答案更好更干净
G
Gum Joe

我遇到了同样的问题,但我找到了一个简单的方法来解决它。如果程序已被用户添加到 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']);

Z
Zack

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

D
Dalton

确保要执行的模块已安装或命令的完整路径(如果它不是节点模块)


R
Rajkumar Bansal

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

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

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

cd root/test/

然后在我的例子中运行你的测试运行器它的摩卡咖啡,所以它会是这样的:

mocha test.js

我浪费了一天多的时间来弄清楚。享受!!


D
Dan Alboteanu

在我的情况下的解决方案

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

虽然这可能是针对特定修复的解决方案,但我看不出它如何有助于调试 ENOENT 的真正原因
我不知道为什么,但是 spawn 调用可以在没有 .cmd 的节点 repl 中工作,但在打字稿开玩笑测试中失败。 - 这个错误可能很难弄清楚,这个答案值得更多的支持。
现有答案已涵盖 .cmd 扩展程序
M
MostlyArmless

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

import { exec, spawn } from 'child_process';

// This works fine
exec('p4 changes -s submitted');

// This gives the ENOENT error
spawn('p4');

// But this resolves it
spawn('p4.exe');
// Even works with the arguments now
spawn('p4.exe', ['changes', '-s', 'submitted']);

D
Danilo Ramirez

我发现的一个案例不在此列表中,但值得添加:

在 Alpine Linux 上,如果可执行文件不兼容,Node 将出现 ENOENT 错误。

Alpine 需要带有 libc 的二进制文件。已使用 glibc 作为系统调用的包装器编译的可执行文件(例如,作为 chromium 的一部分的 chrome)在被 spawn 调用时将失败并显示 ENOENT。


谢谢你的提示
M
MTGradwell

尝试从 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 但您正在运行的程序期望它被称为 node 的其他情况下工作,反之亦然。


J
Joel B

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

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

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

const opts = {
    windowsVerbatimArguments: true
};

你的命令应该恢复正常。

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

不要引用数组内的参数
@laconbass这显然是传达概念的微不足道的示例,因此可以删除引号。但是,在某些情况下,您绝对需要引用参数(例如,如果您需要传递一个路径中带有空格的参数:“C:\Program Files\...”)。我在这里发布它是因为,即使它可能不是您的特定错误案例的原因,它也有望帮助其他遇到这个神秘错误的人,因为 Node 在 Windows 上处理引号,就像我遇到的那样。
node.js 已经制作了一些黑魔法并“正确”地默默引用参数。通过在数组中取消引用参数,您的示例应该可以在没有您提到的未记录选项的情况下工作。
只是为了增加我自己的经验,我正在从 node.js 运行一个 java 进程。这个错误发生在我身上是因为命令周围的引号,而不是参数。在命令路径中使用空格进行测试,它仍然可以在没有引号的情况下使用
S
Steve

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


同样,以某种方式相关的文件系统路径。没有管理员权限,扩展程序可能无法到达路径
S
SkorpEN

在我的情况下删除节点,删除所有 AppData/Roaming/npm 和 AppData/Roaming/npm-cache 并再次安装节点解决问题。


C
Chathurika Sandarenu

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

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.

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


S
Sunil Jakhar

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

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


您的问题似乎与 npm 本身有关,而不是与节点的 child_process.spawn() 有关。似乎是一个 Windows 怪癖
C
Chaya Sandamali

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


P
Paul

模拟器上的本地开发

确保在本地安装了该软件包。通过用 exec 更改 spawn 命令,我得到了一个更详细的错误,并发现我没有安装包。只需运行,检查包是否存在:

brew install imagemagick

Source


E
Emile Bergeron

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

脚步

转到我的计算机和属性单击高级设置然后在环境变量上选择路径然后单击编辑粘贴以下内容(如果不存在):C:\Windows\System32\ 关闭命令提示符运行您要运行的命令

https://i.stack.imgur.com/XCTAf.png


这是 chayasan's answer 的副本