web-dev-qa-db-ja.com

Node.jsで "Error:spawn 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)

修正するためにどのような手順を踏むことができますか?

作者注 :このエラーに関する多くの問題により、今後の参考のためにこの質問を投稿することが推奨されました。

関連質問:

274
laconbass

私は根本的な原因の考えを得るための特定の簡単な方法を見つけました:

Error: spawn ENOENT

このエラーの問題は、コールサイトがどこにあるのか、つまりどの実行可能ファイル/コマンドが見つからないのかを伝えるためのエラーメッセージの情報がほとんどないことです。 。一方、エラーの原因となる正確なコマンドがわかっていれば、 @laconbass 'answer に従って問題を解決できます。

@laconbassの回答で示唆されているように、イベントリスナーをコードのいたるところに追加するのではなく、どのコマンドが問題の原因であるかを突き止めるための非常に簡単な方法を見つけました。重要なアイディアは、スポーン呼び出しに送られた引数を出力するラッパーで元のスポーン呼び出しをラップすることです。

これがラッパー関数です。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が問題を解決するための実行ファイルを見つけることができない理由を見つけることができます。

193
Jiaji Zhou

ステップ1:spawnが正しい方法で呼ばれるようにする

最初に、child_process.spawn(command、args、options)の ドキュメントを確認してください

commandにコマンドライン引数を指定して、指定されたargsで新しいプロセスを起動します。省略した場合、argsはデフォルトで空の配列になります。

3番目の引数は追加のオプションを指定するために使用されます。デフォルトは次のとおりです。

{ cwd: undefined, env: process.env }

新しいプロセスに表示される環境変数を指定するにはenvを使用します。デフォルトはprocess.envです。

commandにコマンドライン引数を指定していないこと、およびspawn呼び出し全体が有効であることを確認してください 。次のステップに進んでください。

ステップ2:エラーイベントを発行しているEvent Emitterを特定する

spawnまたはchild_process.spawnを呼び出すたびに、ソースコードを検索します。

spawn('some-command', [ '--help' ]);

'error'イベント用のイベントリスナをそこにアタッチすると、 'Unhandled'としてそれを投げている正確なEvent Emitterに気付くでしょう。デバッグ後、そのハンドラは削除できます。

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)

最初の2行がまだ

events.js:72
        throw er; // Unhandled 'error' event

そうでないまで、このステップをもう一度実行してください。 次の手順に進む前に、エラーを発行したリスナーを特定する必要があります。

ステップ3:環境変数$PATHが設定されていることを確認してください

考えられるシナリオは2つあります。

  1. デフォルトのspawnの振る舞いに頼るので、子プロセスの環境はprocess.envと同じになります。
  2. あなたは明示的にenvオブジェクトをspawn引数で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を見つけることができなくなるため、ENOENTcommandエラーを発生させます

PATHが正しく設定されたら、次の手順に進みます。 ディレクトリかディレクトリのリストでなければなりません。最後のケースは普通です。

ステップ4:commandPATHで定義されているディレクトリの中に存在することを確認します

ファイル名ENOENT(すなわち、 'some-command')がcommandで定義されたディレクトリの少なくとも1つに存在しない場合、SpawnはPATHエラーを発行するかもしれません。

commandの正確な場所を見つけます。ほとんどのLinuxディストリビューションでは、これはwhichコマンドを使って端末から実行できます。それはあなたに実行可能ファイルへの絶対パス(上記のように)を告げるか、それが見つからないかどうかを告げるでしょう。

コマンドが found の場合のwhichの使用例とその出力

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

コマンドの使用例と が見つからない の場合の出力

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

プログラムのインストールミスが見つからないコマンドの最も一般的な原因です。 必要に応じて各コマンドのドキュメントを参照してインストールしてください。

commandが単純なスクリプトファイルの場合は、PATHのディレクトリからアクセスできることを確認してください。 そうでない場合は、1に移動するか、またはリンクを張ってください。

PATHが正しく設定されていてcommandがそこからアクセス可能であると判断したら、spawn ENOENTをスローしなくても子プロセスを生成できるはずです。

98
laconbass

@DanielImfeldが指摘したように 、オプションに "cwd"を指定した場合、ENOENTがスローされますが、指定されたディレクトリは存在しません。

28
Leeroy Brun

Windowsの解決策:spawnnode-cross-spawn に置き換えます。たとえば、app.jsの冒頭にある以下のようにします。

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

@ 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)イベントが常に発生するためです。そうしないと、最初に使用する場合は、cp.on('error', fn)イベントが最初に発生する可能性があります。

21
Alexander Mills

これに遭遇するかもしれない人のために、他のすべての答えが助けにならず、あなたがWindows上にいるならば、現在 Windows上のspawnの大きな問題 そして特定の呼び出しを引き起こす原因となるPATHEXT環境変数があることを知ってくださいtargetコマンドのインストール方法によっては機能しません。

16
Alex Turpin

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})
    
16
Li Zheng

私の場合、必要な依存システムリソースがインストールされていないために、このエラーが発生していました。

具体的には、ImageMagickを利用しているNodeJSアプリがあります。 npmパッケージがインストールされているにもかかわらず、コアのLinux ImageMagickがインストールされていません。私はImageMagickをインストールするためにapt-getをしました、そしてその後、すべてうまくいきました!

6
PromInc

私は同じ問題に遭遇しました、しかし、私はそれを直す簡単な方法を見つけました。プログラムがユーザーによって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']);
2
Gum Joe

実行されるモジュールがインストールされているか、それがノードモジュールでない場合はコマンドへのフルパスであることを確認します。

1
Dalton

テストケースを実行している間、私はこの厄介な問題も経験していたので、それを乗り越えるために多くの方法を試しました。しかし、私にはうまくいく方法は メインファイルを含むディレクトリからテストランナーを実行することです これには nodejs spawn 関数が含まれます。

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

例えば、この ファイル名はtest.js なので、 それが入っているフォルダーに移動してください 。私の場合は、このようなテストフォルダです。

cd root/test/

それから あなたのテストランナーを実行します 私の場合はそのモカですので、それはこのようになります:

mocha test.js

私はそれを理解するために私の一日以上を無駄にしました。楽しい!!

0
Rajkumar Bansal

より具体的なエラーメッセージを表示するには、spawnの代わりにrequire('child_process').execを使用してください。

例えば:

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);
});
0
de Raad

私の場合の解決策

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');
0
Dan Alboteanu

あなたがWindowsを使っているなら、あなたが知っているコマンドを発行することになるかもしれない引用を扱うときNode.jsはいくらか面白い仕事をします、しかし、Nodeで動かされるときはそうしません。例えば、次のような should work:

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

しかし失敗します。トリックをするように思える引用符/類似物を扱うための幻想的に文書化されていないオプションwindowsVerbatimArgumentsがあります、ちょうどあなたのoptsオブジェクトに以下を追加するようにしてください:

const opts = {
    windowsVerbatimArguments: true
};

そしてあなたの命令は元に戻ります。

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

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']);
0
MostlyArmless

私は窓8のための同じエラーを得ました。問題はあなたのシステムパスの環境変数がないためです。システムのPATH変数に "C:\ Windows\System32 \"という値を追加します。

0
chayasan

Debian LinuxシステムのVS Codeエディタ内からnode.jsプログラムをデバッグしようとしたときにこのエラーが発生しました。私はWindows上で同じことがうまくいったことに気づきました。私が「spawn」コマンドを書いていなかったので、ここで以前に与えられた解決策はあまり役に立ちませんでした。問題のあるコードは、おそらくMicrosoftによって書かれ、VS Codeプログラムの裏側に隠されていました。

次に、node.jsはWindowsではnodeと呼ばれていますが、Debian(そしておそらくUbuntuなどのDebianベースのシステム)ではnodejsと呼ばれています。だから私はエイリアスを作成しました - ルートターミナルから、私は走りました

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

これで問題は解決しました。 node.jsがnodejsと呼ばれているがnodeと呼ばれるプログラムを実行している場合、またはその逆の場合も、同じ手順または類似の手順がおそらくうまくいくでしょう。

0
MTGradwell