540 Stimmen

Wie debugge ich "Fehler: spawn ENOENT" in node.js?

307voto

Jiaji Zhou Punkte 3087

HINWEIS: Dieser Fehler wird fast immer verursacht, weil der Befehl nicht existiert, weil das Arbeitsverzeichnis nicht existiert oder durch einen Windows-spezifischen Fehler.

Ich habe einen besonders einfachen Weg gefunden, um eine Vorstellung von der eigentlichen Ursache des Problems zu bekommen:

Fehler: spawn ENOENT

Das Problem bei diesem Fehler ist, dass in der Fehlermeldung sehr wenig Information vorhanden ist, um Ihnen zu sagen, wo sich die Aufrufstelle befindet, d.h. welches ausführbare Kommando nicht gefunden wird, insbesondere wenn Sie eine große Codebasis haben, in der viele spawn-Aufrufe getätigt werden. Wenn wir andererseits den genauen Befehl kennen, der den Fehler verursacht, können wir der Antwort von @laconbass folgen, um das Problem zu beheben.

Ich habe einen sehr einfachen Weg gefunden, um herauszufinden, welches Kommando das Problem verursacht, anstatt überall in Ihrem Code Event-Listener hinzuzufügen, wie es in der Antwort von @laconbass vorgeschlagen wird. Die Schlüsselidee besteht darin, den ursprünglichen spawn-Aufruf mit einem Wrapper zu umgeben, der die Argumente ausgibt, die an den spawn-Aufruf gesendet werden.

Hier ist die Wrapper-Funktion, platzieren Sie sie oben in der index.js oder irgendeinem anderen Startskript Ihres Servers.

(function() {
    var childProcess = require("child_process");
    var oldSpawn = childProcess.spawn;
    function mySpawn() {
        console.log('spawn aufgerufen');
        console.log(arguments);
        var result = oldSpawn.apply(this, arguments);
        return result;
    }
    childProcess.spawn = mySpawn;
})();

Dann, wenn Sie Ihre Anwendung beim nächsten Mal ausführen, sehen Sie vor der Meldung über die unbehandelte Ausnahme etwas wie folgt:

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

Auf diese Weise können Sie leicht herausfinden, welches Kommando tatsächlich ausgeführt wird, und dann können Sie herausfinden, warum nodejs das ausführbare Programm nicht finden kann, um das Problem zu beheben.

160voto

laconbass Punkte 15514

Schritt 1: Stellen Sie sicher, dass spawn richtig aufgerufen wird

Überprüfen Sie zuerst die Dokumentation für child_process.spawn( command, args, options ):

Startet einen neuen Prozess mit dem angegebenen command und den Befehlszeilenargumenten in args. Wenn weggelassen, ist args standardmäßig ein leeres Array.

Das dritte Argument wird verwendet, um zusätzliche Optionen anzugeben, die standardmäßig sind:

{ cwd: undefined, env: process.env }

Verwenden Sie env, um Umgebungsvariablen festzulegen, die für den neuen Prozess sichtbar sein sollen. Standardmäßig ist dies process.env.

Vergewissern Sie sich, dass Sie keine Befehlszeilenargumente in command eingeben und der gesamte spawn-Aufruf gültig ist. Gehen Sie zum nächsten Schritt über.

Schritt 2: Identifizieren Sie den Ereignisemitter, der das Fehlerereignis auslöst

Durchsuchen Sie Ihren Quellcode nach jedem Aufruf von spawn oder child_process.spawn, z.B.

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

und fügen Sie dort einen Ereignislistener für das 'error'-Ereignis hinzu, damit Sie den genauen Ereignisemitter bemerken, der es als 'Unhandled' wirft. Nach dem Debuggen kann dieser Handler entfernt werden.

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

Führen Sie den Code aus und Sie sollten den Dateipfad und die Zeilennummer erhalten, an der Ihr 'error'-Listener registriert wurde. Etwas Ähnliches wie:

/pfad/der/den/error/listener/registriert.js:29
      throw err;
            ^
Error: spawn ENOENT
    at errnoException (child_process.js:1000:11)
    at Process.ChildProcess._handle.onexit (child_process.js:791:34)

Wenn die ersten beiden Zeilen immer noch

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

sein, führen Sie diesen Schritt erneut aus, bis sie es nicht mehr sind. Sie müssen den Listener identifizieren, der den Fehler auslöst, bevor Sie mit dem nächsten Schritt fortfahren.

Schritt 3: Stellen Sie sicher, dass die Umgebungsvariable $PATH festgelegt ist

Es gibt zwei mögliche Szenarien:

  1. Sie verlassen sich auf das Standardverhalten von spawn, sodass die Umgebung des Kindprozesses die gleiche ist wie process.env.
  2. Sie geben explizit ein env-Objekt an den spawn-Aufruf im options-Argument.

In beiden Szenarien müssen Sie den PATH-Schlüssel im Umgebungsobjekt, das der gestartete Kindprozess verwenden wird, überprüfen.

Beispiel für Szenario 1

// Untersuchen Sie den PATH-Schlüssel auf process.env
console.log( process.env.PATH );
spawn('some-command', ['--help']);

Beispiel für Szenario 2

var env = getEnvKeyValuePairsSomeHow();
// Untersuchen Sie den PATH-Schlüssel im env-Objekt
console.log( env.PATH );
spawn('some-command', ['--help'], { env: env });

Das Fehlen von PATH (d.h., es ist undefined) wird dazu führen, dass spawn den ENOENT-Fehler auslöst, da es nicht möglich sein wird, irgendwelche command zu lokalisieren, es sei denn, es handelt sich um einen absoluten Pfad zur ausführbaren Datei.

Wenn PATH korrekt festgelegt ist, fahren Sie mit dem nächsten Schritt fort. Es sollte ein Verzeichnis oder eine Liste von Verzeichnissen sein. Der letzte Fall ist üblich.

Schritt 4: Stellen Sie sicher, dass command in einem Verzeichnis existiert, das in PATH definiert ist

Spawn kann den ENOENT-Fehler auslösen, wenn der Dateiname command (z.B. 'some-command') nicht in mindestens einem der in PATH definierten Verzeichnisse existiert.

Ermitteln Sie den genauen Speicherort von command. Bei den meisten Linux-Distributionen kann dies über ein Terminal mit dem Befehl which erfolgen. Es wird Ihnen den absoluten Pfad zur ausführbaren Datei mitteilen (wie oben) oder angeben, dass sie nicht gefunden wurde.

Beispiel für die Verwendung von which und dessen Ausgabe, wenn ein Befehl gefunden wird

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

Beispiel für die Verwendung von which und dessen Ausgabe, wenn ein Befehl nicht gefunden wird

> which some-command
bash: type: some-command: nicht gefunden

Falsch installierte Programme sind die häufigste Ursache für einen Befehl, der als nicht gefunden markiert ist. Konsultieren Sie die Dokumentation jedes Befehls bei Bedarf und installieren Sie ihn.

Wenn der Befehl eine einfache Skriptdatei ist, stellen Sie sicher, dass er von einem Verzeichnis auf dem PATH aus zugänglich ist. Wenn nicht, bewegen Sie ihn dorthin oder erstellen Sie eine Verknüpfung dazu.

Wenn Sie feststellen, dass PATH korrekt festgelegt ist und command davon aus zugänglich ist, sollte es möglich sein, Ihren Kindprozess ohne das Werfen von ENONT zu starten.

108voto

kia nasirzadeh Punkte 2328

Durch Hinzufügen der shell: true Option wurde mein Problem gelöst:

Der folgende Code ist fehlerhaft unter Windows:

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

Workaround:

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

Basierend auf der Node.js Dokumentation (Danke an @Boris Kommentar):

Beachten Sie:

Wenn die Option shell aktiviert ist, übergeben Sie keine unsauberen Benutzereingaben an diese Funktion. Jede Eingabe, die Shell-Metazeichen enthält, kann zur Auslösung beliebiger Befehlsausführungen verwendet werden.

46voto

Leeroy Brun Punkte 4448

Wie @DanielImfeld es angemerkt hat, wird ENOENT ausgelöst, wenn Sie "cwd" in den Optionen angeben, aber das angegebene Verzeichnis nicht existiert.

33voto

Nilzor Punkte 17395

Windows-Lösung: Ersetzen Sie spawn durch node-cross-spawn. Zum Beispiel so am Anfang Ihrer app.js:

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

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X