Bagaimana cara saya men-debug "Error: spawn ENOENT" di node.js?

350

Ketika saya mendapatkan kesalahan berikut:

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)

Prosedur apa yang bisa saya ikuti untuk memperbaikinya?

Catatan penulis : Banyak masalah dengan kesalahan ini mendorong saya untuk mengirim pertanyaan ini untuk referensi di masa mendatang.

Pertanyaan-pertanyaan Terkait:

laconbass
sumber
Dalam kasus saya, saya meneruskan seluruh perintah sebagai String seperti yang Anda lakukan dengan execbukannya meneruskan perintah sebagai argumen pertama dan opsi sebagai Array untuk argumen kedua. misal saya spawn( "adb logcat -c" )malah melakukan spawn( "adb", [ "logcat", "-c" ] ).
Joshua Pinter

Jawaban:

235

CATATAN: Kesalahan ini hampir selalu disebabkan karena perintah tidak ada, karena direktori kerja tidak ada, atau dari bug khusus windows.

Saya menemukan cara mudah tertentu untuk mendapatkan ide tentang penyebab utama:

Error: spawn ENOENT

Masalah dari kesalahan ini adalah, hanya ada sedikit informasi dalam pesan kesalahan untuk memberi tahu Anda di mana situs panggilan berada, yaitu yang dapat dieksekusi / perintah tidak ditemukan, terutama ketika Anda memiliki basis kode besar di mana ada banyak panggilan pemijahan . Di sisi lain, jika kita tahu perintah pasti yang menyebabkan kesalahan maka kita bisa mengikuti jawaban @laconbass untuk memperbaiki masalah.

Saya menemukan cara yang sangat mudah untuk menemukan perintah mana yang menyebabkan masalah daripada menambahkan pendengar acara di mana pun dalam kode Anda seperti yang disarankan dalam jawaban @laconbass. Gagasan utamanya adalah untuk membungkus panggilan spawn asli dengan pembungkus yang mencetak argumen yang dikirim ke spawn call.

Inilah fungsi wrapper, letakkan di bagian atas index.jsatau apa pun skrip awal server Anda.

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

Kemudian saat berikutnya Anda menjalankan aplikasi Anda, sebelum pesan pengecualian yang tidak tertangkap, Anda akan melihat sesuatu seperti itu:

spawn called
{ '0': 'hg',
  '1': [],
  '2':
   { cwd: '/* omitted */',
     env: { IP: '0.0.0.0' },
     args: [] } }

Dengan cara ini Anda dapat dengan mudah mengetahui perintah mana yang benar-benar dieksekusi dan kemudian Anda dapat mengetahui mengapa nodejs tidak dapat menemukan yang dapat dieksekusi untuk memperbaiki masalah.

Jiaji Zhou
sumber
3
Berikut ide lain: hanya mengubah spawn()ke exec()dan coba lagi. exec()akan memberi tahu Anda perintah apa yang coba dijalankan.
Adam Monsen
1
Penting: Pastikan menempatkan kode di atas sedekat mungkin dengan awal file JS utama. Jika Anda memuat modul lain terlebih dahulu, mereka dapat menyembunyikan fungsi 'spawn' dan override di sini tidak akan pernah dipanggil.
Dan Nissenbaum
1
Saya tidak beruntung menggunakan skrip. Itu tidak bekerja sama sekali.
newguy
Jadi bagaimana Anda menggunakan metode ini dalam file kasar? Saya tidak yakin di mana harus meletakkan ini.
Felix Eve
2
Ini bekerja dengan baik untuk saya. Saya hanya meletakkan ini di bagian atas file gulpfile.js saya, dan bingo bango bongo, spawn logging!
Yann Duran
121

Langkah 1: Pastikan spawn disebut dengan cara yang benar

Pertama, tinjau dokumen untuk child_process.spawn (perintah, args, opsi) :

Meluncurkan proses baru dengan yang diberikan command, dengan argumen baris perintah di args. Jika dihilangkan,args default ke Array kosong.

Argumen ketiga digunakan untuk menentukan opsi tambahan, yang secara default adalah:

{ cwd: undefined, env: process.env }

Gunakan envuntuk menentukan variabel lingkungan yang akan terlihat oleh proses baru, standarnya adalah process.env.

Pastikan Anda tidak memasukkan argumen baris perintah apa pun commanddan seluruh spawnpanggilan itu valid . Lanjutkan ke langkah selanjutnya.

Langkah 2: Identifikasi Emitor Peristiwa yang memancarkan peristiwa kesalahan

Cari pada kode sumber Anda untuk setiap panggilan ke spawn, atau child_process.spawn, yaitu

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

dan lampirkan di sana pendengar acara untuk acara 'kesalahan', sehingga Anda dapat mengetahui Peristiwa Emitor yang tepat yang melemparkannya sebagai 'Tidak Ditangani'. Setelah debugging, pawang itu dapat dihapus.

spawn('some-command', [ '--help' ])
  .on('error', function( err ){ throw err })
;

Jalankan dan Anda harus mendapatkan jalur file dan nomor baris tempat pendaftar 'kesalahan' Anda terdaftar. Sesuatu seperti:

/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)

Jika dua baris pertama masih

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

lakukan langkah ini lagi sampai tidak. Anda harus mengidentifikasi pendengar yang memancarkan kesalahan sebelum melanjutkan ke langkah berikutnya.

Langkah 3: Pastikan variabel lingkungan $PATH diatur

Ada dua skenario yang mungkin:

  1. Anda mengandalkan spawnperilaku default , sehingga lingkungan proses anak akan sama dengan process.env.
  2. Anda explicity melewati sebuah envobjek untuk spawndi optionsargumen.

Dalam kedua skenario, Anda harus memeriksa PATHkunci pada objek lingkungan yang akan digunakan proses anak yang dilahirkan.

Contoh untuk skenario 1

// inspect the PATH key on process.env
console.log( process.env.PATH );
spawn('some-command', ['--help']);

Contoh untuk skenario 2

var env = getEnvKeyValuePairsSomeHow();
// inspect the PATH key on the env object
console.log( env.PATH );
spawn('some-command', ['--help'], { env: env });

Tidak adanya PATH(yaitu, itu undefined) akan menyebabkan spawnmemancarkan ENOENTkesalahan , karena itu tidak akan mungkin untuk menemukan apa pun commandkecuali itu adalah jalur absolut ke file yang dapat dieksekusi.

Ketika PATHdiatur dengan benar, lanjutkan ke langkah berikutnya. Itu harus berupa direktori, atau daftar direktori. Kasus terakhir adalah biasa.

Langkah 4: Pastikan commandada di direktori yang ditentukan dalamPATH

Bibit dapat memancarkan ENOENTkesalahan jika nama file command(yaitu, 'beberapa perintah') tidak ada di setidaknya satu direktori yang ditentukan PATH.

Temukan tempat yang tepat dari command. Pada kebanyakan distribusi linux, ini dapat dilakukan dari terminal dengan whichperintah. Ini akan memberi tahu Anda jalur absolut ke file yang dapat dieksekusi (seperti di atas), atau memberi tahu jika itu tidak ditemukan.

Contoh penggunaan yang mana dan hasilnya ketika suatu perintah ditemukan

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

Contoh penggunaan yang mana dan hasilnya ketika suatu perintah tidak ditemukan

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

program yang salah pasang adalah penyebab paling umum untuk perintah yang tidak ditemukan .Lihat setiap dokumentasi perintah jika perlu dan pasang.

Ketika perintah adalah file skrip sederhana memastikan itu dapat diakses dari direktori di PATH. Jika tidak, pindahkan ke salah satu atau buat tautan ke sana.

Setelah Anda menentukan PATHdiatur dengan benar dan commanddapat diakses dari itu, Anda harus dapat menelurkan proses anak Anda tanpa spawn ENOENTdilemparkan.

laconbass
sumber
1
Ini sangat membantu saya dalam debugging Spawn ENOENT. Saya telah merujuknya beberapa kali. Terima kasih!
CodeManiak
36
Saya juga menemukan bahwa ENOENT akan dilemparkan jika Anda menentukan cwddalam opsi, tetapi direktori yang diberikan tidak ada.
Daniel Imfeld
4
@DanielImfeld TOTAL SAVIOR. Anda harus menulis jawaban yang mengatakan ini.
GreenAsJade
4
Bila Anda menggunakan spawn('some-command', ['--help'], { env: env });seperti yang dicontohkan oleh Langkah 3 dalam jawaban ini dan melewati lingkungan kustom, pastikan untuk menentukan PATH, misalnya: { env: { PATH: process.env.PATH } }. Opsi env tidak akan mewarisi variabel dari env Anda saat ini secara default.
anty
5
Saya dapat menyelesaikan masalah saya dengan memberikan shell: trueopsi spawn.
Nickofthyme
35

Seperti yang ditunjukkan oleh @DanielImfeld , ENOENT akan dilemparkan jika Anda menentukan "cwd" pada opsi, tetapi direktori yang diberikan tidak ada.

Leeroy Brun
sumber
1
jadi apakah ada cara untuk mengeksekusi di direktori tertentu perintah?
Mitro
Di Windows (7) tampaknya Anda juga perlu memasukkan huruf drive di cwdjalur: 'c: / ...' dan bukan hanya '/ ...'
Museful
29

Solusi Windows: Ganti spawndengan node-cross-spawn . Misalnya seperti ini di awal app.js Anda:

(function() {
    var childProcess = require("child_process");
    childProcess.spawn = require('cross-spawn');
})(); 
Nilzor
sumber
2
berfungsi kecuali itu adalah drop-in, tidak perlu untuk proses child_. Cara yang persis sama dengan menelurkan node atau spawnSync, jadi setetes penggantian var spawn = require('cross-spawn'); // Spawn NPM asynchronously var child = spawn('npm', ['list', '-g', '-depth', '0'], { stdio: 'inherit' });
Bogdan Trusca
27

Jawaban @ laconbass membantu saya dan mungkin paling benar.

Saya datang ke sini karena saya salah menggunakan spawn. Sebagai contoh sederhana:

ini salah:

const s = cp.spawn('npm install -D suman', [], {
    cwd: root
});

ini salah:

const s = cp.spawn('npm', ['install -D suman'], {
    cwd: root
});

ini benar:

const s = cp.spawn('npm', ['install','-D','suman'], {
    cwd: root
});

namun, saya sarankan melakukannya dengan cara ini:

const s = cp.spawn('bash');
s.stdin.end(`cd "${root}" && npm install -D suman`);
s.once('exit', code => {
   // exit
});

ini karena cp.on('exit', fn)nanti acara akan selalu menyala, selama bash diinstal, jika tidak, cp.on('error', fn)acara tersebut akan diaktifkan terlebih dahulu, jika kita menggunakannya dengan cara pertama, jika kita meluncurkan 'npm' secara langsung.

Alexander Mills
sumber
1
Berpikir untuk refactoring jawaban saya untuk memberikan "panduan umum", dan meninggalkan detail untuk setiap penyebab masalah (kehilangan dependensi, panggilan salah, lingkungan salah, ...).
laconbass
2
semua orang yang menyukai jawaban ini, mungkin juga tertarik dengan alternatif asli ini: gist.github.com/ORESoftware/7bf225f0045b4649de6848f1ea5def4c
Alexander Mills
1
Downvoted karena jika apa yang ingin Anda miliki adalah shell maka anda harus menggunakan child_process.execatau lulus shell: trueuntuk spawn.
givanse
@ givanse belum tentu benar - Anda mungkin ingin menjalankan zsh atau bash atau fsh tergantung pada shell apa yang ingin Anda gunakan, dan perilakunya juga berbeda
Alexander Mills
22

Untuk ENOENT di Windows, https://github.com/nodejs/node-v0.x-archive/issues/2318#issuecomment-249355505 memperbaikinya.

mis. ganti spawn ('npm', ['-v'], {stdio: 'inherit'}) dengan:

  • untuk semua versi node.js:

    spawn(/^win/.test(process.platform) ? 'npm.cmd' : 'npm', ['-v'], {stdio: 'inherit'})
  • untuk node.js 5.x dan yang lebih baru:

    spawn('npm', ['-v'], {stdio: 'inherit', shell: true})
Li Zheng
sumber
1
Di mana melakukan modifikasi ini?
Deilan
8
Bagian kuncinya adalah menambahkanshell: true
Ted Nyberg
19

Bagi siapa pun yang mungkin menemukan ini, jika semua jawaban lain tidak membantu dan Anda berada di Windows, ketahuilah bahwa saat ini ada masalah besar dengan spawnWindows dan PATHEXTvariabel lingkungan yang dapat menyebabkan panggilan tertentu untuk muncul tidak berfungsi tergantung pada seberapa perintah target diinstal.

Alex Turpin
sumber
2
Dan apa solusinya?
Nilzor
6
Menggunakan node-cross-spawn bekerja untuk saya. Lihat jawaban di bawah: stackoverflow.com/a/35561971/507339
Nilzor
1
Selama berabad-abad berusaha menemukan apa yang salah dan ini akhirnya menjadi masalah. Saya menyerah spawndan hanya digunakan execsebagai gantinya.
reduckted
8

Dalam kasus saya, saya mendapatkan kesalahan ini karena sumber daya sistem dependen yang diperlukan tidak diinstal.

Lebih khusus lagi, saya memiliki aplikasi NodeJS yang menggunakan ImageMagick. Meskipun memiliki paket npm yang diinstal, inti Linux ImageMagick tidak diinstal. Saya melakukan apt-get untuk menginstal ImageMagick dan setelah itu semua bekerja dengan baik!

PromInc
sumber
Apakah windows perlu menginstal ImageMagick juga? Saya menguji pada windows dan mendapatkan error
Somename
6

di windows, cukup menambahkan shell: trueopsi menyelesaikan masalah saya:

salah:

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

benar:

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

Apakah Anda mengubah envopsi?

Kemudian lihat jawaban ini.


Saya mencoba untuk menelurkan proses simpul dan TIL bahwa Anda harus menyebarkan variabel lingkungan yang ada ketika Anda menelurkan lagi Anda akan kehilangan PATHvariabel lingkungan dan mungkin yang penting lainnya.

Ini adalah perbaikan untuk saya:

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',
  }
});
Rico Kahler
sumber
4

Sebelum siapa pun menghabiskan banyak waktu untuk debugging masalah ini, sebagian besar waktu itu dapat diatasi dengan menghapus node_modulesdan menginstal ulang paket.

Untuk memasang:

Jika ada file kunci yang mungkin Anda gunakan

yarn install --frozen-lockfile

atau

npm ci

dengan hormat. jika tidak maka

yarn install

atau

npm i
InsOp
sumber
Wow solusi yang sangat sederhana dan berhasil untuk saya! Setiap orang harus mencoba ini terlebih dahulu untuk melihat apakah itu menyelesaikan masalah.
Nick K
2

Saya mengalami masalah yang sama, tetapi saya menemukan cara sederhana untuk memperbaikinya. Tampaknya ada spawn()kesalahan jika program telah ditambahkan ke PATH oleh pengguna (mis. Perintah sistem normal berfungsi).

Untuk memperbaiki ini, Anda dapat menggunakan modul yang mana ( 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']);
Joe Gum
sumber
2

Gunakan require('child_process').execalih-alih menelurkan untuk pesan kesalahan yang lebih spesifik!

sebagai contoh:

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

Pastikan modul yang akan dieksekusi dipasang atau path lengkap ke perintah jika bukan modul simpul

Dalton
sumber
1

Saya juga mengalami masalah yang menjengkelkan ini saat menjalankan test case saya, jadi saya mencoba banyak cara untuk mengatasinya. Tetapi cara kerjanya bagi saya adalah dengan menjalankan test runner Anda dari direktori yang berisi file utama Anda yang mencakup fungsi nodejs Anda menelurkan sesuatu seperti ini:

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

Misalnya, nama file ini adalah test.js , jadi pindah saja ke folder yang berisi itu . Dalam kasus saya, ini adalah folder tes seperti ini:

cd root/test/

maka dari menjalankan uji pelari Anda dalam kasus saya moka sehingga akan menjadi seperti ini:

mocha test.js

Saya telah menghabiskan lebih dari satu hari untuk mencari tahu. Nikmati!!

Rajkumar Bansal
sumber
1

Saya mengalami masalah ini pada Windows, di mana memanggil execdan spawndengan perintah yang sama persis (menghilangkan argumen) bekerja dengan baik untuk exec(jadi saya tahu perintah saya aktif $PATH), tetapi spawnakan memberikan ENOENT. Ternyata saya hanya perlu menambahkan .exeperintah yang saya gunakan:

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']);
Sebagian besar tanpa kesalahan
sumber
0

Saya mendapatkan kesalahan ini ketika mencoba men-debug program node.js dari dalam editor VS Code pada sistem Linux Debian. Saya perhatikan hal yang sama berfungsi dengan baik pada Windows. Solusi yang sebelumnya diberikan di sini tidak banyak membantu karena saya belum menulis perintah "spawn". Kode yang menyinggung itu kemungkinan ditulis oleh Microsoft dan disembunyikan di bawah kap program VS Code.

Selanjutnya saya perhatikan bahwa node.js disebut node pada Windows tetapi pada Debian (dan mungkin pada sistem berbasis Debian seperti Ubuntu) itu disebut nodejs. Jadi saya membuat alias - dari terminal root, saya berlari

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

dan ini memecahkan masalah. Prosedur yang sama atau serupa mungkin akan bekerja dalam kasus lain di mana node.js Anda disebut nodejs tetapi Anda menjalankan program yang mengharapkannya disebut node, atau sebaliknya.

MTGradwell
sumber
0

Jika Anda menggunakan Windows Node.js melakukan beberapa bisnis lucu ketika menangani kutipan yang dapat mengakibatkan Anda mengeluarkan perintah yang Anda tahu berfungsi dari konsol, tetapi tidak ketika dijalankan di Node. Misalnya, yang berikut ini harus berfungsi:

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

tetapi gagal. Ada opsi yang tidak berdokumen fantastis windowsVerbatimArgumentsuntuk menangani kutipan / serupa yang tampaknya melakukan trik, pastikan untuk menambahkan berikut ini ke objek opts Anda:

const opts = {
    windowsVerbatimArguments: true
};

dan perintah Anda harus kembali berbisnis.

 spawn('ping', ['"8.8.8.8"'], { windowsVerbatimArguments: true });
Joel B
sumber
Jangan mengutip argumen di dalam array
laconbass
@ laconbass Ini adalah contoh yang jelas sepele untuk menyampaikan konsep dan sehingga kutipan dapat dihapus. Namun, ada beberapa kasus di mana Anda benar-benar perlu mengutip argumen (misalnya jika Anda perlu memberikan argumen yang memiliki lintasan dengan spasi di dalamnya: "C: \ Program Files \ ..." ). Saya mempostingnya di sini karena, meskipun itu mungkin bukan penyebab kasus kesalahan spesifik Anda, semoga akan membantu orang lain yang mengalami kesalahan samar ini karena penanganan Node pada kutipan pada Windows seperti yang saya temui.
Joel B
node.js sudah membuat beberapa Ilmu Hitam dan diam-diam mengutip argumen "dengan benar". Contoh Anda harus bekerja tanpa opsi tidak berdokumen yang Anda sebutkan, dengan menghapus tanda kutip di dalam array.
laconbass
Hanya untuk menambah pengalaman saya sendiri, saya sedang menjalankan proses java dari node. Kesalahan ini terjadi pada saya karena kutipan di sekitar perintah, bukan argumen. Uji dengan spasi di jalur perintah dan masih berfungsi tanpa tanda kutip
Troncoso
0

solusi dalam kasus saya

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');
Dan Alboteanu
sumber
1
Meskipun ini mungkin merupakan solusi untuk perbaikan spesifik yang menang, saya tidak melihat bagaimana ini membantu untuk debug penyebab sebenarnya dari ENOENT
laconbass
Saya tidak tahu mengapa, tetapi panggilan spawn akan bekerja di node repl tanpa .cmd, tetapi gagal dalam tes jest mengetik naskah. - Kesalahan ini bisa sangat sulit untuk dipecahkan, jawaban ini pantas mendapatkan lebih banyak suara.
Mathieu CAROFF
0

Jika Anda mengalami masalah ini dengan aplikasi yang sumbernya tidak dapat Anda modifikasi, pertimbangkan untuk menggunakannya dengan variabel lingkungan yang NODE_DEBUGdisetel child_process, misalnya NODE_DEBUG=child_process yarn test. Ini akan memberi Anda informasi yang baris perintah telah dipanggil di direktori mana dan biasanya detail terakhir adalah alasan kegagalan.

Karl Richter
sumber
0

Meskipun mungkin merupakan lintasan lingkungan atau masalah lain bagi sebagian orang, saya baru saja menginstal ekstensi Workshop Lateks untuk Visual Studio Code pada Windows 10 dan melihat kesalahan ini ketika mencoba membangun / melihat PDF. Menjalankan VS Code ketika Administrator memecahkan masalah untuk saya.

Steve
sumber
1
Sekali lagi, terkait lakukan path sistem file dengan cara tertentu. Ekstensi mungkin tidak dapat mencapai jalur tanpa izin admin
laconbass
-1

Saya mendapat kesalahan yang sama untuk windows 8. Masalahnya adalah karena variabel lingkungan dari jalur sistem Anda hilang. Tambahkan nilai "C: \ Windows \ System32 \" ke variabel PATH sistem Anda.

Chaya Sandamali
sumber
-2

Tambahkan C:\Windows\System32\ke pathvariabel lingkungan.

Langkah

  1. Buka komputer dan properti saya

  2. Klik pada Pengaturan lanjutan

  3. Kemudian pada variabel Lingkungan

  4. Pilih Pathdan kemudian klik edit

  5. Rekatkan yang berikut jika belum ada: C:\Windows\System32\

  6. Tutup prompt perintah

  7. Jalankan perintah yang ingin Anda jalankan

Tangkapan layar variabel Windows 8 Environment

vmit dhawan
sumber
3
Ini adalah duplikat dari jawaban Yayasan
Emile Bergeron