web-dev-qa-db-fra.com

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

Quand 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 résoudre ce problème?

Note de l’auteur: de nombreux problèmes liés à cette erreur m’ont incité à poser cette question pour référence future.

Questions connexes:

248
laconbass

J'ai trouvé un moyen particulièrement facile de se faire une idée de la cause fondamentale de:

Error: spawn ENOENT

Le problème de cette erreur est qu’il ya très 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 n’est pas trouvé, en particulier lorsque vous avez une base de code volumineuse où il y a beaucoup d’appels spawn . D'autre part, si nous connaissons la commande exacte qui cause l'erreur, nous pouvons suivre @laconbass 'answer pour résoudre le problème.

J'ai trouvé un moyen très facile de repérer quelle commande posait le 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 principale est d'encapsuler l'appel spawn d'origine avec un wrapper qui imprime les arguments envoyés à l'appel spawn.

Voici la fonction wrapper, placez-la en haut du index.js ou 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 comprendre pourquoi nodejs ne peut pas trouver l'exécutable pour résoudre le problème.

184
Jiaji Zhou

Étape 1: Assurez-vous que spawn est appelé de la bonne manière

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

Lance un nouveau processus avec la variable command donnée, avec des arguments de ligne de commande dans args. Si omis, args est défini par défaut sur un tableau vide.

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

{ cwd: undefined, env: process.env }

Utilisez env pour 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 placer d'argument de ligne de commande dans command et que l'appel spawn dans son ensemble est valide. Passez à l'étape suivante.

Étape 2: Identifiez l'émetteur de l'événement qui émet l'événement d'erreur

Recherchez votre code source pour chaque appel à spawn ou child_process.spawn, c.-à-d.

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 renvoie 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-le et vous devriez obtenir le chemin du fichier et le numéro de ligne où votre écouteur "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 encore

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

refaites 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 $PATH est définie

Il y a deux scénarios possibles:

  1. Vous utilisez le comportement par défaut spawn. L'environnement du processus enfant sera donc identique à process.env.
  2. Vous passez explicitement un objet env à spawn sur l'argument options.

Dans les deux scénarios, vous devez inspecter la clé PATH sur l'objet d'environnement utilisé par le processus enfant engendré.

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) fera que spawn émettra l'erreur ENOENT, car il ne sera pas possible de localiser un command sauf s'il s'agit d'un chemin absolu vers le fichier exécutable.

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

Étape 4: Assurez-vous que command existe dans un répertoire de ceux définis dans PATH

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

Localisez le lieu exact de command. Sur la plupart des distributions Linux, cela peut être fait depuis un terminal avec la commande which. Il vous indiquera le chemin absolu du fichier exécutable (comme ci-dessus), ou vous indiquera s'il est introuvable.

Exemple d'utilisation et de son résultat lorsqu'une commande est trouvé

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

Exemple d'utilisation et de son résultat lorsqu'une commande est introuvable

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

Les programmes miss-installés sont la cause la plus courante d'une commande non trouvée. Reportez-vous à la documentation de chaque commande si nécessaire et installez-la.

La commande When est un simple fichier script garantissant qu'il est accessible depuis un répertoire de la variable PATH. Si ce n'est pas le cas, déplacez-le ou créez un lien vers celui-ci.

Une fois que vous avez déterminé que PATH est correctement défini et que command est accessible à partir de celle-ci, vous devriez pouvoir générer votre processus enfant sans que spawn ENOENT soit lancé.

93
laconbass

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

27
Leeroy Brun

Solution Windows: remplacez spawn par 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');
})(); 
22
Nilzor

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

Je suis venu ici parce que j’utilisais spawn de manière incorrecte… .. À titre d’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 vous 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'événement cp.on('exit', fn) sera toujours déclenché, tant que bash est installé, sinon l'événement cp.on('error', fn) pourrait se déclencher en premier, si nous l'utilisons de la première façon, si nous lançons directement 'npm'. 

18
Alexander Mills

Pour tous ceux qui pourraient tomber sur cela, si toutes les autres réponses ne vous aident pas et que vous êtes sur Windows, sachez qu'il existe actuellement un gros problème avec spawn sous Windows et la variable d'environnement PATHEXT pouvant entraîner certains appels spawn ne fonctionnera pas en fonction de l’installation de la commande cible.

15
Alex Turpin

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

par exemple. remplace 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})
    
13
Li Zheng

Dans mon cas, cette erreur s'est produite parce que les ressources système dépendantes nécessaires n'ont pas été installées.

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

6
PromInc

Assurez-vous que le module à exécuter est installé ou le chemin complet de la commande s'il ne s'agit pas d'un module de noeud. 

1
Dalton

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

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

Je passais également par ce problème ennuyeux lors de l’exécution de mes cas de test, j’ai donc essayé de nombreuses manières de le résoudre. Mais la façon dont cela fonctionne pour moi est de lancer votre programme d’essai à partir du répertoire qui contient votre fichier principal qui contient votre nodejs spawn function quelque chose comme ceci:

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

Par exemple, le nom de fichier est test.js , donc déplacez simplement vers le dossier qui le contient . Dans mon cas, c'est un dossier de test comme ceci:

cd root/test/

puis à partir de lancez votre coureur de test dans mon cas, son moka sera le suivant:

mocha test.js

J'ai passé plus d'une journée à comprendre. Prendre plaisir!!

0
Rajkumar Bansal

Utilisez require('child_process').exec au 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);
});
0
de Raad

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

Si vous utilisez Windows Node.js, vous pouvez vous amuser avec des citations, ce qui peut vous obliger à exécuter une commande dont vous savez qu'il fonctionne à partir de la console, mais qui ne fonctionne pas dans Node. Par exemple, le devrait travail:

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

mais échoue. Il existe une option fantastiquement non documentée windowsVerbatimArguments pour la gestion des 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 });
0
Joel B

J'ai rencontré ce problème sous Windows, où appeler exec et spawn avec exactement la même commande (en omettant les arguments) fonctionnait correctement pour exec (donc je savais que ma commande était sur $PATH), mais spawn donnerait ENOENT. Il s'est avéré que je devais simplement 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']);
0
MostlyArmless

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

0
chayasan

J'avais cette erreur en essayant de déboguer un programme node.js depuis l'éditeur de code VS sur un système Linux Debian. J'ai remarqué que la même chose fonctionnait correctement sous Windows. Les solutions données précédemment n'étaient pas d'une grande aide 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 s'appelle node sous Windows, mais sous Debian (et vraisemblablement sur des systèmes Debian comme Ubuntu), il s'appelle nodejs. J'ai donc créé un alias - à partir d'un terminal root, j'ai exécuté 

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 vraisemblablement dans les autres cas où votre node.js s'appelle nodejs mais que vous exécutez un programme qui s'attend à ce qu'il s'appelle node ou inversement.

0
MTGradwell