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

本文翻譯自:How do I debug “Error: spawn ENOENT” on node.js?

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: 相關問題:


#1樓

參考:https://stackoom.com/question/1sB7c/如何在node-js上調試-錯誤-生成ENOENT


#2樓

Step 1: Ensure 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 in args . 使用給定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 is process.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. 繼續進行下一步。

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 , ie 在源代碼中搜索對spawnchild_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 $PATH is set 步驟3:確保設置了環境變量$PATH

There are two possible scenarios: 有兩種可能的方案:

  1. You rely on the default spawn behaviour, so child process environment will be the same as process.env . 您依賴於默認的spawn行爲,因此子進程環境將與process.env相同。
  2. You are explicity passing an 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. 最後一種情況是通常的。

Step 4: Ensure 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


#3樓

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無法找到可執行程序來解決該問題。


#4樓

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的工作,之後一切都變好了!


#5樓

對於任何人誰可能偶然發現了這一點,如果所有其他的答案不幫助你,你是在Windows上,知道的是,目前有一個很大的問題, spawn在WindowsPATHEXT環境變量,可能會導致某些呼叫產卵到不行視關於如何安裝目標命令。


#6樓

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');
})(); 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章