[英]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 找不到可執行文件來解決問題。
spawn
首先,查看child_process.spawn( command, args, options )的文檔:
使用給定的
command
啟動一個新進程,命令行參數在args
。 如果省略,args
默認為空數組。第三個參數用於指定附加選項,默認為:
{ cwd: undefined, env: process.env }
使用
env
指定對新進程可見的環境變量,默認為process.env
。
確保您不會把任何命令行參數的command
,整個spawn
呼叫是有效的。 繼續下一步。
搜索每次調用spawn
或child_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
再次執行此步驟,直到它們不是。 在繼續下一步之前,您必須確定發出錯誤的偵聽器。
$PATH
有兩種可能的情況:
spawn
行為,因此子進程環境將與process.env
相同。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
,繼續下一步。 它應該是一個目錄或目錄列表。 最后一種情況是常見的。
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 上spawn
和PATHEXT
環境變量存在一個大問題,可能會導致某些調用 spawn 無法工作,具體取決於關於目標命令的安裝方式。
child_process.spawn
,感謝@ child_process.spawn
-zhou。 簡單、快速,2015 年 1 月環境問題
PATH
環境變量指定的目錄中。僅限 Windows 的錯誤/怪癖
錯誤的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
有兩個可能的起源:
- 您正在編寫的代碼
- 你依賴的代碼
當來源是您依賴的代碼時,通常的原因是環境問題(或 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 上遇到了這個問題,其中使用完全相同的命令(省略參數)調用exec
和spawn
對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']);
我在 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 LTS
、 gulp v3.9.1
ruby 3.1
、捆綁器bundler 2.4.5
、jekyll jekyll 4.2.2
這行代碼是我在spawn
和bundle
中遇到的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
環境變量中。
轉到我的計算機和屬性
點擊高級設置
然后在環境變量上
選擇Path
,然后點擊編輯
粘貼以下內容(如果尚不存在): C:\\Windows\\System32\\
關閉命令提示符
運行你想運行的命令
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.