簡體   English   中英

如何在 node.js 上調試“錯誤:生成 ENOENT”?

[英]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)

我可以按照什么程序來修復它?

作者注:這個錯誤的很多問題鼓勵我發布這個問題以供將來參考。

相關問題:

注意:此錯誤幾乎總是由於命令不存在、工作目錄不存在或僅 Windows 的錯誤引起的。

我找到了一種特別簡單的方法來了解以下問題的根本原因:

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 找不到可執行文件來解決問題。

第 1 步:確保以正確的方式調用spawn

首先,查看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對象以在options參數上spawn

在這兩種情況下,您都必須檢查生成的子進程將使用的環境對象上的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定義的目錄中

如果PATH定義的至少一個目錄中不存在 filename 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

未安裝的程序是未找到命令的最常見原因。 如果需要,請參閱每個命令文檔並安裝它。

當 command 是一個簡單的腳本文件時,確保它可以從PATH上的目錄訪問。 如果不是,請將其移至其中一個或建立指向它的鏈接。

一旦確定正確設置了PATH並且可以從中訪問command ,您應該能夠生成子進程而不會拋出spawn ENOENT

正如@DanielImfeld 指出的那樣,如果您在選項中指定“cwd”,則將拋出 ENOENT,但給定的目錄不存在。

的Windows解決方案:更換spawn節點交叉產卵 例如在 app.js 的開頭是這樣的:

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

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

這是因為cp.on('exit', fn)事件將始終觸發,只要安裝了 bash,否則, cp.on('error', fn)事件可能首先觸發,如果我們使用它第一種方式,如果我們直接啟動'npm'。

對於 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})

在 Windows 中,只需添加shell: true選項即可解決我的問題:

不正確:

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

正確的:

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

對於可能偶然發現此問題的任何人,如果所有其他答案都沒有幫助並且您使用的是 Windows,請知道當前在 Windows 上spawnPATHEXT環境變量存在一個大問題,可能會導致某些調用 spawn 無法工作,具體取決於關於目標命令的安裝方式。

如何研究引發錯誤的 spawn 調用:

已知的常見原因

  1. 環境問題

    • 系統中不存在該命令可執行文件(未安裝依賴項)。 prominc 的回答
    • 命令可執行文件不存在於PATH環境變量指定的目錄中。
  2. 僅限 Windows 的錯誤/怪癖

  3. 錯誤的spawn('command', ['--argument', 'list'], { cwd, env, ...opts })用法

    • 指定的工作目錄 ( opts.cwd ) 不存在 ·leeroy-brun 的回答
    • 命令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有兩個可能的起源:

  1. 您正在編寫的代碼
  2. 你依賴的代碼

當來源是您依賴的代碼時,通常的原因是環境問題(或 Windows 怪癖)


就我而言,由於沒有安裝必要的依賴系統資源,我拋出了這個錯誤。

更具體地說,我有一個使用 ImageMagick 的 NodeJS 應用程序。 盡管安裝了 npm 包,但沒有安裝核心 Linux ImageMagick。 我做了一個 apt-get 來安裝 ImageMagick,之后一切都很好!

在任何人花費大量時間調試此問題之前,大多數情況下可以通過刪除node_modules並重新安裝軟件包來解決。

安裝:

如果存在鎖定文件,您可能會使用

yarn install --frozen-lockfile

或者

npm ci

分別。 如果不是那么

yarn install

或者

npm i

您是否正在更改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',
  }
});

如果您在無法修改源的應用程序中遇到此問題,請考慮將環境變量NODE_DEBUG設置為child_process來調用它,例如NODE_DEBUG=child_process yarn test 這將為您提供在哪個目錄中調用了哪些命令行的信息,通常最后一個細節是失敗的原因。

我遇到了同樣的問題,但我找到了一種簡單的方法來解決它。 如果程序已被用戶添加到 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']);

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

確保要執行的模塊已安裝或命令的完整路徑(如果它不是節點模塊)

我在運行測試用例時也遇到了這個煩人的問題,所以我嘗試了很多方法來解決它。 但是對我有用的方法是從包含您的主文件的目錄運行您的測試運行程序,其中包含您的nodejs spawn函數,如下所示:

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

例如,此文件名為 test.js ,因此只需移至包含它的文件夾即可 就我而言,它是這樣的測試文件夾:

cd root/test/

然后在我的情況下運行你的測試運行器它的 mocha 所以它會是這樣的:

mocha test.js

我已經浪費了一天多的時間來弄清楚。 享受!!

我在 Windows 上遇到了這個問題,其中使用完全相同的命令(省略參數)調用execspawnexec工作正常(所以我知道我的命令在$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']);

我在 Debian Linux 系統上嘗試從 VS Code 編輯器中調試 node.js 程序時遇到此錯誤。 我注意到同樣的事情在 Windows 上運行正常。 之前在這里給出的解決方案沒有太大幫助,因為我沒有編寫任何“生成”命令。 有問題的代碼大概是由 Microsoft 編寫的,並隱藏在 VS Code 程序的幕后。

接下來,我注意到 node.js 在 Windows 上被稱為 node,但在 Debian(大概在基於 Debian 的系統,如 Ubuntu)上,它被稱為 nodejs。 所以我創建了一個別名 - 從根終端,我跑了

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

這解決了問題。 相同或類似的過程可能適用於您的 node.js 被稱為 nodejs 但您正在運行的程序希望它被稱為 node 的其他情況,反之亦然。

如果你使用的是 Windows Node.js 在處理引號時會做一些有趣的事情,這可能會導致你發出一個你知道從控制台運行的命令,但在 Node.js 中運行時卻不會。 例如,以下應該工作:

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

但失敗了。 有一個非常無證的選項windowsVerbatimArguments用於處理引號/類似似乎可以解決問題,只需確保將以下內容添加到您的 opts 對象中:

const opts = {
    windowsVerbatimArguments: true
};

你的命令應該恢復正常工作。

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

在我的情況下的解決方案

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

盡管對某些人來說這可能是環境路徑或其他問題,但我剛剛在 Windows 10 上安裝了 Visual Studio Code 的 Latex Workshop 擴展,並在嘗試構建/預覽 PDF 時看到了此錯誤。 以管理員身份運行 VS Code 為我解決了這個問題。

在我的情況下,刪除節點,刪除所有 AppData/Roaming/npm 和 AppData/Roaming/npm-cache 並再次安裝節點解決問題。

最近我也遇到了類似的問題。

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 更改該配置解決了我的問題。

我發現的一個案例不在此列表中,但值得添加:

在 Alpine Linux 上,如果可執行文件不兼容,Node 將顯示 ENOENT 錯誤。

Alpine 需要帶有libc二進制文件。 使用glibc作為系統調用的包裝器編譯的可執行文件(例如, chrome作為 Chromium 的一部分)在被spawn調用時將失敗並顯示 ENOENT。

模擬器本地開發

ImageMagick 預裝在firebase 雲中,但是在本地開發中,模擬器沒有這個包……還沒有。

brew install imagemagick

另一個提示:使用exec更改spawn命令以獲得更詳細的錯誤。 你可能會發現functions: ReferenceError: exec is not defined這意味着你的包沒有安裝。

來源

對我來說,我在 package.json 中進行了以下更改。

  "version": "0.0.0",
  "scripts": {
    "dev": "vite --open",    // delete this line
    "dev": "vite",           // with this one
   .....
  }

我在Powershell on Windows 11構建 gulp gulp-jekyll jekyll 時出現了這個。

nodejs 10 LTSgulp v3.9.1 ruby 3.1 、捆綁器bundler 2.4.5 、jekyll jekyll 4.2.2

這行代碼是我在spawnbundle中遇到的ENOENT問題的原因。

  return cp.spawn('bundle', [
    'exec', 
    'jekyll', 
    'build', 
    '--source=app', '--destination=build/development', '--config=_config.yml', '--profile'
  ], { stdio: 'inherit' })
  .on('close', done);

返回了兩個錯誤,故障排除應該從這里開始。

events.js:174
      throw er; // Unhandled 'error' event
      ^
Error: spawn bundle ENOENT

cp.spawn沒有處理錯誤事件,因此使用簡單的console.log()處理該事件將通過調試信息暴露真正的錯誤:

  return cp.spawn('bundle', [
    'exec', 
    'jekyll', 
    'build', 
    '--source=app', '--destination=build/development', '--config=_config.yml', '--profile'
  ], { stdio: 'inherit' })
  .on('error', (e) => console.log(e))
  .on('close', done);

這現在提供了更多的調試信息。

{ Error: spawn bundle ENOENT
  errno: 'ENOENT',
  code: 'ENOENT',
  syscall: 'spawn bundle',
  path: 'bundle',
  spawnargs:
   [ 'exec',
     'jekyll',
     'build',
     '--source=app',
     '--destination=build/development',
     '--config=_config.yml',
     '--profile' ] }

調試的下一步是使用child_process.spawn(command[, args][, options])nodejs 10 LTS文檔。 如上所述,將{ shell: true }添加到 spawn 的選項中是一個可行的解決方案。 這也解決了我的問題。

  { stdio: 'inherit', shell: true }

這個解決方案只是一個創可貼,可以重構以處理所有環境,但是在 scope 中如何解決和調試nodejs上的spawn ENOENT錯誤是超出了范圍。

我在 Windows 8 上遇到了同樣的錯誤。問題是因為缺少系統路徑的環境變量。 將 "C:\\Windows\\System32\\" 值添加到您的系統 PATH 變量中。

嘗試了一切都沒有用,我的系統有不同的問題。

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

C:\\Windows\\System32\\path環境變量中。

腳步

  1. 轉到我的計算機和屬性

  2. 點擊高級設置

  3. 然后在環境變量上

  4. 選擇Path ,然后點擊編輯

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

  6. 關閉命令提示符

  7. 運行你想運行的命令

Windows 8 環境變量截圖

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM