Comment déboguer «Erreur: spawn ENOENT» sur node.js?

350

Lorsque j'obtiens l'erreur suivante:

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)

Quelle procédure puis-je suivre pour le réparer?

Note de l'auteur : Beaucoup de problèmes avec cette erreur m'ont encouragé à poster cette question pour de futures références.

Questions connexes:

laconbass
la source
Dans mon cas, je passais la commande entière sous forme de chaîne comme vous le feriez avec execau lieu de passer la commande comme premier argument et les options comme tableau pour le deuxième argument. par exemple, je faisais spawn( "adb logcat -c" )au lieu de spawn( "adb", [ "logcat", "-c" ] ).
Joshua Pinter

Réponses:

235

Remarque: cette erreur est presque toujours provoquée parce que la commande n'existe pas, parce que le répertoire de travail n'existe pas ou à partir d'un bogue Windows uniquement.

J'ai trouvé un moyen particulièrement simple de se faire une idée de la cause première de:

Error: spawn ENOENT

Le problème de cette erreur est qu'il y a vraiment peu d'informations dans le message d'erreur pour vous dire où se trouve le site d'appel, c'est-à-dire quel exécutable / commande est introuvable, surtout lorsque vous avez une grande base de code où il y a beaucoup d'appels d'apparition . D'un autre côté, si nous connaissons la commande exacte à l'origine de l'erreur, nous pouvons suivre la réponse de @laconbass pour résoudre le problème.

J'ai trouvé un moyen très facile de repérer la commande à l'origine du problème plutôt que d'ajouter des écouteurs d'événements partout dans votre code, comme suggéré dans la réponse de @laconbass. L'idée clé est d'encapsuler l'appel de spawn d'origine avec un wrapper qui affiche les arguments envoyés à l'appel de spawn.

Voici la fonction wrapper, placez-la en haut du index.jsou quel que soit le script de démarrage de votre serveur.

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

Ensuite, la prochaine fois que vous exécuterez votre application, avant le message de l'exception non capturée, vous verrez quelque chose comme ça:

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

De cette façon, vous pouvez facilement savoir quelle commande est réellement exécutée, puis vous pouvez découvrir pourquoi nodejs ne peut pas trouver l'exécutable pour résoudre le problème.

Jiaji Zhou
la source
3
Voici une autre idée: passez simplement spawn()à exec()et réessayez. exec()vous dira quelle commande il a essayé d'exécuter.
Adam Monsen
1
Important: veillez à placer le code ci-dessus le plus près possible du début du fichier JS principal. Si vous chargez d'autres modules en premier, ils peuvent cacher la fonction 'spawn' et le remplacement ici ne sera jamais appelé.
Dan Nissenbaum
1
Je n'ai aucune chance d'utiliser le script. Ça ne marche pas du tout.
newguy
Alors, comment utiliseriez-vous cette méthode dans un fichier grunt? Je ne sais pas où mettre ça.
Felix Eve
2
Cela a parfaitement fonctionné pour moi. Je viens de mettre cela en haut de mon fichier gulpfile.js et bingo bango bongo, spawn logging!
Yann Duran
121

Étape 1: Assurez spawn- vous que le nom est le bon

Tout d'abord, passez en revue les documents pour child_process.spawn (commande, arguments, options) :

Lance un nouveau processus avec la donnée command, avec des arguments de ligne de commande dans args. S'il est omis, par argsdéfaut , un tableau est vide.

Le troisième argument est utilisé pour spécifier des options supplémentaires, par défaut:

{ cwd: undefined, env: process.env }

Utilisez envpour spécifier les variables d'environnement qui seront visibles par le nouveau processus, la valeur par défaut est process.env.

Assurez-vous de ne pas insérer d'arguments de ligne de commande commandet que l' spawnappel entier est valide . Passez à l'étape suivante.

Étape 2: identifier l'émetteur d'événements qui émet l'événement d'erreur

Recherche sur votre code source pour chaque appel à spawn, ou child_process.spawn, par exemple

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

et attachez-y un écouteur d'événement pour l'événement «erreur», afin que vous remarquiez l'émetteur d'événement exact qui le lance comme «non géré». Après le débogage, ce gestionnaire peut être supprimé.

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

Exécutez et vous devriez obtenir le chemin du fichier et le numéro de ligne où votre écouteur "d'erreur" a été enregistré. Quelque chose comme:

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

Si les deux premières lignes sont toujours

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

recommencez cette étape jusqu'à ce qu'ils ne le soient pas. Vous devez identifier l'écouteur qui émet l'erreur avant de passer à l'étape suivante.

Étape 3: assurez-vous que la variable d'environnement $PATHest définie

Il existe deux scénarios possibles:

  1. Vous comptez sur le spawncomportement par défaut , donc l'environnement de processus enfant sera le même que process.env.
  2. Vous êtes explicitement en train de passer un envobjet à spawnl' optionsargument.

Dans les deux scénarios, vous devez inspecter la PATHclé de l'objet d'environnement que le processus enfant généré utilisera.

Exemple pour le scénario 1

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

Exemple pour le scénario 2

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

L'absence de PATH(c'est-à-dire, c'est undefined) provoquera l'émission spawnde l' ENOENTerreur , car il ne sera pas possible de localiser tout commandsauf s'il s'agit d'un chemin absolu vers le fichier exécutable.

Lorsque PATHest correctement réglé, passez à l'étape suivante. Il doit s'agir d'un répertoire ou d'une liste de répertoires. Le dernier cas est l'habituel.

Étape 4: Assurez-vous qu'il commandexiste sur un répertoire de ceux définis dansPATH

Spawn peut émettre l' ENOENTerreur si le nom de fichier command(c'est-à-dire, 'some-command') n'existe pas dans au moins un des répertoires définis sur PATH.

Localisez l'endroit exact de command. Sur la plupart des distributions Linux, cela peut être fait à partir d'un terminal avec la whichcommande. Il vous indiquera le chemin absolu vers le fichier exécutable (comme ci-dessus), ou dira s'il n'est pas trouvé.

Exemple d'utilisation de laquelle et de sa sortie lorsqu'une commande est trouvée

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

Exemple d'utilisation de laquelle et de sa sortie lorsqu'une commande n'est pas trouvée

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

les programmes mal installés sont la cause la plus courante d'une commande introuvable . Reportez-vous à la documentation de chaque commande si nécessaire et installez-la.

Lorsque la commande est un simple fichier de script, assurez-vous qu'elle est accessible à partir d'un répertoire sur le PATH. Si ce n'est pas le cas, déplacez-le vers l'un ou faites un lien vers celui-ci.

Une fois que vous avez déterminé qu'il PATHest correctement défini et qu'il commandest accessible à partir de celui-ci, vous devriez pouvoir générer votre processus enfant sans spawn ENOENTêtre jeté.

laconbass
la source
1
Cela a été très utile pour mon débogage de Spawn ENOENT. Je l'ai référencé plusieurs fois. Merci!
CodeManiak
36
J'ai également constaté que ENOENT sera levé si vous spécifiez cwddans les options, mais le répertoire donné n'existe pas.
Daniel Imfeld
4
@DanielImfeld TOTAL SAVIOR. Vous devez écrire une réponse qui dit ceci.
GreenAsJade
4
Lorsque vous utilisez spawn('some-command', ['--help'], { env: env });comme illustré par l' étape 3 dans cette réponse et passez un environnement personnalisé, assurez - vous de spécifier le PATH, par exemple: { env: { PATH: process.env.PATH } }. L'option env n'héritera pas les variables de votre env actuel par défaut.
anty
5
J'ai pu résoudre mon problème en passant shell: trueaux options d'apparition.
Nickofthyme le
35

Comme l'a souligné @DanielImfeld , ENOENT sera lancé si vous spécifiez "cwd" dans les options, mais le répertoire donné n'existe pas.

Leeroy Brun
la source
1
existe-t-il donc un moyen d'exécuter la commande dans un répertoire spécifique?
Mitro
Dans Windows (7), il semble que vous devez également inclure la lettre de lecteur dans le cwdchemin: 'c: / ...' et pas seulement '/ ...'
Museful
29

Solution Windows: remplacer spawnpar node-cross-spawn . Par exemple, comme ceci au début de votre app.js:

(function() {
    var childProcess = require("child_process");
    childProcess.spawn = require('cross-spawn');
})(); 
Nilzor
la source
2
a fonctionné sauf qu'il s'agit d'un drop-in, pas besoin de child_process. Exactement de la même manière que le spawn ou la spawnSync du nœud, c'est donc une goutte de remplacement. var spawn = require('cross-spawn'); // Spawn NPM asynchronously var child = spawn('npm', ['list', '-g', '-depth', '0'], { stdio: 'inherit' });
Bogdan Trusca
27

La réponse de @ laconbass m'a aidé et est probablement la plus correcte.

Je suis venu ici parce que j'utilisais incorrectement le spawn. Comme exemple simple:

Ceci est une erreur:

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

Ceci est une erreur:

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

c'est correct:

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

cependant, je recommande de le faire de cette façon:

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

cela est dû au fait que l' cp.on('exit', fn)événement se déclenchera toujours, tant que bash est installé, sinon, l' cp.on('error', fn)événement peut se déclencher en premier, si nous l'utilisons de la première manière, si nous lançons directement 'npm'.

Alexander Mills
la source
1
Penser à refactoriser ma réponse pour fournir un "guide général", et laisser des détails à chaque cause du problème (dépendances manquées, appels incorrects, mauvais environnement, ...).
laconbass
2
tous ceux qui aiment cette réponse peuvent également être intéressés par cette alternative native: gist.github.com/ORESoftware/7bf225f0045b4649de6848f1ea5def4c
Alexander Mills
1
Downvoted parce que si ce que vous voulez avoir un shell, vous devez utiliser child_process.execou passer shell: trueà spawn.
givanse
@givanse pas nécessairement vrai - vous pouvez exécuter zsh ou bash ou fsh selon le shell que vous souhaitez utiliser, et le comportement est également différent
Alexander Mills
22

Pour ENOENT sous Windows, https://github.com/nodejs/node-v0.x-archive/issues/2318#issuecomment-249355505 le corrige.

par exemple remplacer spawn ('npm', ['-v'], {stdio: 'inherit'}) par:

  • pour toutes les versions de node.js:

    spawn(/^win/.test(process.platform) ? 'npm.cmd' : 'npm', ['-v'], {stdio: 'inherit'})
  • pour node.js 5.x et versions ultérieures:

    spawn('npm', ['-v'], {stdio: 'inherit', shell: true})
Li Zheng
la source
1
Où faire ces modifications?
Deilan
8
La partie clé ajouteshell: true
Ted Nyberg
19

Pour tous ceux qui pourraient tomber dessus, si toutes les autres réponses ne vous aident pas et que vous êtes sous Windows, sachez qu'il existe actuellement un gros problème avec spawnsous Windows et la PATHEXTvariable d'environnement qui peut entraîner le rejet de certains appels selon la façon dont la commande cible est installée.

Alex Turpin
la source
2
Et quelle est la solution?
Nilzor
6
L'utilisation de node-cross-spawn a fonctionné pour moi. Voir la réponse ci-dessous: stackoverflow.com/a/35561971/507339
Nilzor
1
J'ai passé des siècles à essayer de trouver ce qui n'allait pas et cela a fini par être le problème. J'ai abandonné et j'ai spawnjuste utilisé à la execplace.
reduckted
8

Dans mon cas, je recevais cette erreur car les ressources système dépendantes nécessaires n'étaient pas installées.

Plus précisément, j'ai une application NodeJS qui utilise ImageMagick. Bien que le package npm soit installé, le noyau Linux ImageMagick n'a pas été installé. J'ai fait un apt-get pour installer ImageMagick et après cela tout a bien fonctionné!

PromInc
la source
Windows a-t-il également besoin d'installer ImageMagick? Im test sur windows et erreur
Somename
6

dans les fenêtres, ajouter simplement une shell: trueoption a résolu mon problème:

Incorrect:

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

correct:

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

Modifiez-vous l' envoption?

Regardez ensuite cette réponse.


J'essayais de générer un processus de nœud et TIL que vous devriez répartir les variables d'environnement existantes lorsque vous générez sinon vous perdrez le PATH variable d'environnement et éventuellement d'autres importantes.

C'était la solution pour moi:

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
la source
4

Avant que quiconque ne passe trop de temps à déboguer ce problème, la plupart du temps, il peut être résolu en supprimant node_moduleset en réinstallant les packages.

À installer:

Si un fichier de verrouillage existe, vous pouvez utiliser

yarn install --frozen-lockfile

ou

npm ci

respectivement. sinon

yarn install

ou

npm i
InsOp
la source
Wow une solution si simple et cela a fonctionné pour moi! Tout le monde devrait essayer ceci en premier pour voir si cela résout le problème.
Nick K
2

J'ai rencontré le même problème, mais j'ai trouvé un moyen simple de le résoudre. Il semble y avoir des spawn()erreurs si le programme a été ajouté au PATH par l'utilisateur (par exemple, les commandes système normales fonctionnent).

Pour résoudre ce problème, vous pouvez utiliser le module 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']);
Gum Joe
la source
2

Utilisez require('child_process').execau lieu de spawn pour un message d'erreur plus spécifique!

par exemple:

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
la source
1

Assurez-vous que le module à exécuter est installé ou le chemin d'accès complet à la commande s'il ne s'agit pas d'un module de nœud

Dalton
la source
1

Je traversais également ce problème ennuyeux lors de l'exécution de mes cas de test, j'ai donc essayé de nombreuses façons de le contourner. Mais la façon dont cela fonctionne pour moi est d' exécuter votre lanceur de test à partir du répertoire qui contient votre fichier principal qui inclut votre fonction de génération de nodejs quelque chose comme ceci:

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

Par exemple, ce nom de fichier est test.js , alors déplacez-vous simplement vers le dossier qui le contient . Dans mon cas, c'est un dossier de test comme celui-ci:

cd root/test/

puis exécutez votre testeur dans mon cas, son moka donc ce sera comme ceci:

mocha test.js

J'ai perdu plus d'une journée pour le comprendre. Prendre plaisir!!

Rajkumar Bansal
la source
1

J'ai rencontré ce problème sous Windows, où appeler execet spawnavec exactement la même commande (en omettant les arguments) fonctionnait bien exec(donc je savais que ma commande était activée $PATH), mais spawndonnerait ENOENT. Il s'est avéré que je devais juste ajouter .exeà la commande que j'utilisais:

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']);
Surtout sans bras
la source
0

J'obtenais cette erreur lorsque j'essayais de déboguer un programme node.js depuis l'éditeur VS Code sur un système Linux Debian. J'ai remarqué que la même chose fonctionnait bien sous Windows. Les solutions précédemment données ici ne m'ont pas beaucoup aidé car je n'avais écrit aucune commande "spawn". Le code incriminé a probablement été écrit par Microsoft et caché sous le capot du programme VS Code.

Ensuite, j'ai remarqué que node.js est appelé node sur Windows mais sur Debian (et probablement sur les systèmes basés sur Debian tels que Ubuntu) il s'appelle nodejs. J'ai donc créé un alias - à partir d'un terminal racine, j'ai couru

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

et cela a résolu le problème. La même procédure ou une procédure similaire fonctionnera probablement dans d'autres cas où votre node.js est appelé nodejs mais vous exécutez un programme qui s'attend à ce qu'il soit appelé node, ou vice-versa.

MTGradwell
la source
0

Si vous êtes sous Windows, Node.js fait des affaires drôles lors de la gestion des devis qui peuvent vous amener à émettre une commande dont vous savez qu'elle fonctionne à partir de la console, mais pas lorsqu'elle est exécutée dans Node. Par exemple, les éléments suivants devraient fonctionner:

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

mais échoue. Il existe une option incroyablement non documentée windowsVerbatimArgumentspour gérer les guillemets / similaires qui semble faire l'affaire, assurez-vous simplement d'ajouter ce qui suit à votre objet opts:

const opts = {
    windowsVerbatimArguments: true
};

et votre commande devrait être de retour dans les affaires.

 spawn('ping', ['"8.8.8.8"'], { windowsVerbatimArguments: true });
Joel B
la source
Ne citez pas les arguments à l'intérieur du tableau
laconbass
@laconbass Ceci est un exemple évidemment trivial pour transmettre le concept et donc les guillemets pourraient être supprimés. Cependant, il existe des cas où vous devez absolument citer les arguments (par exemple, si vous devez passer un argument qui contient un chemin avec un espace: "C: \ Program Files \ ..." ). Je l'ai posté ici car, même si cela n'a peut-être pas été la cause de votre cas d'erreur spécifique, cela aidera, espérons-le, quelqu'un d'autre à rencontrer cette erreur cryptique à cause de la gestion des citations par Node sur Windows comme je l'ai rencontré.
Joel B
node.js crée déjà de la magie noire et cite silencieusement les arguments "correctement". Votre exemple devrait fonctionner sans l'option non documentée que vous mentionnez, en supprimant les arguments à l'intérieur du tableau.
laconbass
Juste pour ajouter ma propre expérience, j'exécutais un processus java à partir du nœud. Cette erreur m'est arrivée à cause des guillemets autour de la commande, plutôt que de l'argument. Testez avec des espaces dans le chemin de commande et cela fonctionne toujours sans guillemets
Troncoso
0

solution dans mon cas

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
la source
1
Bien que cela puisse être une solution pour gagner des correctifs spécifiques, je ne vois pas comment cela aide à déboguer la véritable cause de l'ENOENT
laconbass
Je n'ai aucune idée pourquoi, mais l'appel de spawn fonctionnerait dans la repl de noeud sans le .cmd, mais échouerait dans un test de plaisanterie dactylographié. - Cette erreur peut être assez difficile à comprendre, cette réponse mérite plus de votes positifs.
Mathieu CAROFF
0

Si vous rencontrez ce problème avec une application dont vous ne pouvez pas modifier la source, envisagez de l'invoquer avec la variable d'environnement NODE_DEBUGdéfinie sur child_process, par exemple NODE_DEBUG=child_process yarn test. Cela vous fournira des informations sur les lignes de commande qui ont été invoquées dans quel répertoire et généralement le dernier détail est la raison de l'échec.

Karl Richter
la source
0

Bien qu'il puisse s'agir d'un chemin d'environnement ou d'un autre problème pour certaines personnes, je venais d'installer l'extension Latex Workshop pour Visual Studio Code sur Windows 10 et j'ai vu cette erreur lors de la tentative de création / prévisualisation du PDF. L'exécution de VS Code en tant qu'administrateur a résolu le problème pour moi.

Steve
la source
1
Encore une fois, le chemin du système de fichiers est lié d'une manière ou d'une autre. L'extension ne peut probablement pas atteindre un chemin sans les autorisations d'administrateur
laconbass
-1

J'ai la même erreur pour Windows 8. Le problème est dû au fait qu'une variable d'environnement de votre chemin d'accès système est manquante. Ajoutez la valeur "C: \ Windows \ System32 \" à la variable PATH de votre système.

Chaya Sandamali
la source
-2

Ajouter C:\Windows\System32\aupath variable d'environnement.

Pas

  1. Accéder à mon ordinateur et à mes propriétés

  2. Cliquez sur Paramètres avancés

  3. Puis sur les variables d'environnement

  4. Sélectionnez Pathpuis cliquez sur modifier

  5. Collez les éléments suivants s'ils ne sont pas déjà présents: C:\Windows\System32\

  6. Fermez l'invite de commande

  7. Exécutez la commande que vous vouliez exécuter

Capture d'écran des variables d'environnement Windows 8

vmit dhawan
la source
3
Ceci est un double de la réponse
Emile Bergeron