How do I debug "Error: spawn ENOENT" on node.js?
Solution 1
How to research the spawn call raising the error:
- Use NODE_DEBUG=child_process, Credits to @karl-richter. Simple, quick, October 2019
-
Use a wrapper to decorate
child_process.spawn
, Credits to @jiaji-zhou. Simple, quick, January 2015 - Long procedure, credits to @laconbass. Complex, time-cost, December 2014
Known, usual causes
-
Environment issues
- The command executable does not exist within the system (dependency not being installed). see prominc's answer
- The command executable does not exist within a directory of those specified by
PATH
environment variable. - The executable binary was compiled with uncompatible libraries. see danilo-ramirez answer
-
Windows-only bugs/quirks
- '.cmd' extension / shell: true. see li-zheng answer
- Administrator permisions. see steve's answer
-
Wrong
spawn('command', ['--argument', 'list'], { cwd, env, ...opts })
usage- Specified working directory (
opts.cwd
) does not exist · see leeroy-brun's answer - Argument list within command
String
spawn('command --wrong --argument list')
- Env vars within command string
spawn('ENV_VAR=WRONG command')
- Argument list
Array
specified asString
spawn('cmd', '--argument list')
- Unset
PATH
env variable=>spawn('cmd', [], { env: { variable } }
spawn('cmd', [], { env: { ...process.env, variable } }
- Specified working directory (
There are 2 posible origins for
ENOENT
:
- Code you are writing
- Code you depend on
When origin is code you depend on, usual cause is an Environment Issue (or windows quirk)
Solution 2
NOTE: This error is almost always caused because the command does not exist, because the working directory does not exist, or from a windows-only bug.
I found a particular easy way to get the idea of the root cause of:
Error: spawn ENOENT
The problem of this error is, there is really little information in the error message to tell you where the call site is, i.e. which executable/command is not found, especially when you have a large code base where there are a lot of spawn calls. On the other hand, if we know the exact command that cause the error then we can follow @laconbass' answer to fix the problem.
I found a very easy way to spot which command cause the problem rather than adding event listeners everywhere in your code as suggested in @laconbass' answer. The key idea is to wrap the original spawn call with a wrapper which prints the arguments send to the spawn call.
Here is the wrapper function, put it at the top of the index.js
or whatever your server's starting script.
(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;
})();
Then the next time you run your application, before the uncaught exception's message you will see something like that:
spawn called
{ '0': 'hg',
'1': [],
'2':
{ cwd: '/* omitted */',
env: { IP: '0.0.0.0' },
args: [] } }
In this way you can easily know which command actually is executed and then you can find out why nodejs cannot find the executable to fix the problem.
Solution 3
Step 1: Ensure spawn
is called the right way
First, review the docs for child_process.spawn( command, args, options ):
Launches a new process with the given
command
, with command line arguments inargs
. If omitted,args
defaults to an empty Array.The third argument is used to specify additional options, which defaults to:
{ cwd: undefined, env: process.env }
Use
env
to specify environment variables that will be visible to the new process, the default isprocess.env
.
Ensure you are not putting any command line arguments in command
and the whole spawn
call is valid. Proceed to next step.
Step 2: Identify the Event Emitter that emits the error event
Search on your source code for each call to spawn
, or child_process.spawn
, i.e.
spawn('some-command', [ '--help' ]);
and attach there an event listener for the 'error' event, so you get noticed the exact Event Emitter that is throwing it as 'Unhandled'. After debugging, that handler can be removed.
spawn('some-command', [ '--help' ])
.on('error', function( err ){ throw err })
;
Execute and you should get the file path and line number where your 'error' listener was registered. Something like:
/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)
If the first two lines are still
events.js:72
throw er; // Unhandled 'error' event
do this step again until they are not. You must identify the listener that emits the error before going on next step.
Step 3: Ensure the environment variable $PATH
is set
There are two possible scenarios:
- You rely on the default
spawn
behaviour, so child process environment will be the same asprocess.env
. - You are explicity passing an
env
object tospawn
on theoptions
argument.
In both scenarios, you must inspect the PATH
key on the environment object that the spawned child process will use.
Example for scenario 1
// inspect the PATH key on process.env
console.log( process.env.PATH );
spawn('some-command', ['--help']);
Example for scenario 2
var env = getEnvKeyValuePairsSomeHow();
// inspect the PATH key on the env object
console.log( env.PATH );
spawn('some-command', ['--help'], { env: env });
The absence of PATH
(i.e., it's undefined
) will cause spawn
to emit the ENOENT
error, as it will not be possible to locate any command
unless it's an absolute path to the executable file.
When PATH
is correctly set, proceed to next step. It should be a directory, or a list of directories. Last case is the usual.
Step 4: Ensure command
exists on a directory of those defined in PATH
Spawn may emit the ENOENT
error if the filename command
(i.e, 'some-command') does not exist in at least one of the directories defined on PATH
.
Locate the exact place of command
. On most linux distributions, this can be done from a terminal with the which
command. It will tell you the absolute path to the executable file (like above), or tell if it's not found.
Example usage of which and its output when a command is found
> which some-command
some-command is /usr/bin/some-command
Example usage of which and its output when a command is not found
> which some-command
bash: type: some-command: not found
miss-installed programs are the most common cause for a not found command. Refer to each command documentation if needed and install it.
When command is a simple script file ensure it's accessible from a directory on the PATH
. If it's not, either move it to one or make a link to it.
Once you determine PATH
is correctly set and command
is accessible from it, you should be able to spawn your child process without spawn ENOENT
being thrown.
Solution 4
As @DanielImfeld pointed it, ENOENT will be thrown if you specify "cwd" in the options, but the given directory does not exist.
Solution 5
in windows, simply adding shell: true
option solved my problem:
incorrect:
const { spawn } = require('child_process');
const child = spawn('dir');
correct:
const { spawn } = require('child_process');
const child = spawn('dir', [], {shell: true});
laconbass
I love rhythm. The rhythm in music, at the flow of source code lines, at life... I love following that rhythm, break it down, faster, slowler, STOP. And start again... #SOreadytohelp
Updated on July 08, 2022Comments
-
laconbass almost 2 years
When I get the following error:
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)
What procedure can I follow to fix it?
Author note: Lots of issues with this error encouraged me to post this question for future references.
Related questions:
- using spawn function with NODE_ENV=production
- node.js child_process.spawn ENOENT error - only under supervisord
- spawn ENOENT node.js error
- https://stackoverflow.com/questions/27603713/nodejs-spawn-enoent-error-on-travis-calling-global-npm-package
- Node JS - child_process spawn('npm install') in Grunt task results in ENOENT error
- Running "foreman" task Fatal error: spawn ENOENT
- unhandled error event in node js Error: spawn ENOENT at errnoException (child_process.js:975:11)
- Node.js SpookyJS: error executing hello.js
- https://stackoverflow.com/questions/26572214/run-grunt-on-a-directory-nodewebkit
- Run exe file with Child Process NodeJS
- Node: child_process.spawn not working on Java even though it's in the path (ENOENT)
- spawn ENOENT error with NodeJS (PYTHON related)
- image resizing is not working in node.js (partial.js) (non-installed dependency)
- npm install error ENOENT (build dependency problem)
- Cannot install node.js - oracle module on Windows 7 (build dependency problem)
- Error installing gulp using nodejs on windows (strange case)
-
Adam Monsen about 9 yearsHere's another idea: just change
spawn()
toexec()
and try again.exec()
will tell you what command it tried to run. -
fredrikekelund about 9 yearsThe problem for me was indeed that
PATH
was undefined. Do you know what causes this? I asked a question about it as well stackoverflow.com/questions/29652582/… -
laconbass about 9 yearsI remember a time it was
undefined
because the way I was spawning the node proccess. -
Dan Nissenbaum almost 9 yearsImportant: Make sure to place the code above as close to the start of the main JS file as possible. If you load other modules first, they can stash away the 'spawn' function and the override here will never be called.
-
CodeManiak almost 9 yearsThis has been very helpful to my debugging of Spawn ENOENT. I've referenced it multiple times. Thanks!
-
Alexander Mills over 8 yearsif it's an ENOENT error, why would the command not be recognized on the OS? it seems reasonable that the command is recognized but something is wrong with reading the file itself...
-
laconbass over 8 years@AlexMills Usually the situation you describe is reported as EACCES
-
Daniel Imfeld over 8 yearsI've also found that ENOENT will be thrown if you specify
cwd
in the options, but the given directory does not exist. -
GreenAsJade over 8 years@DanielImfeld TOTAL SAVIOUR. You should write an answer that says this.
-
cdaringe about 8 yearsI have a linux box and an osx box, both node versions reporting using v4.2.4. On the OSX machine if a try/catch wrap a call to spawn('bogus-binary', ...), it lands in the catch statement. in the linux box, it shows up in the event emitter. this is wild.
-
laconbass about 8 years@cdaringe please post a new question with the code and let's see what the problem may be
-
Nilzor about 8 yearsAnd what's the solution?
-
Nilzor about 8 yearsUsing node-cross-spawn worked for me. See answer below: stackoverflow.com/a/35561971/507339
-
laconbass about 8 yearsThinking on refactoring my answer to provide a "general guide", and leaving details to each cause of the problem (miss dependencies, incorrect calls, wrong environment,...).
-
anty over 7 yearsWhen you are using
spawn('some-command', ['--help'], { env: env });
as exemplified by Step 3 in this answer and are passing a custom environment, be sure to specify thePATH
, for instance:{ env: { PATH: process.env.PATH } }
. The env option will not inherit variables from your current env by default. -
reduckted over 7 yearsSpent ages trying to find what was wrong and this ended up being the problem. I gave up on
spawn
and just usedexec
instead. -
Bogdan Trusca over 7 yearsworked except it is a drop-in, no need for child_process. Exactly the same way as node's spawn or spawnSync, so it's a drop in replacement.
var spawn = require('cross-spawn');
// Spawn NPM asynchronously var child = spawn('npm', ['list', '-g', '-depth', '0'], { stdio: 'inherit' });
-
Emile Bergeron over 7 yearsThis is a duplicate of chayasan's answer
-
newguy over 7 yearsI have no luck using the script. It doesn't work at all.
-
Felix Eve about 7 yearsSo how would you use this method in a grunt file? I'm not sure where to put this.
-
Yann Duran about 7 yearsThis worked perfectly for me. I just put this at the top of my gulpfile.js file, and bingo bango bongo, spawn logging!
-
Somename about 7 yearsDoes windows need ImageMagick installed as well? Im testing on windows and getting error
-
Deilan almost 7 yearsWhere to do these modifications?
-
laconbass almost 7 yearsDon't quote the arguments inside the array
-
Joel B almost 7 years@laconbass This is an obviously trivial example to convey the concept and so the quotes could be removed. However, there are cases where you absolutely need to quote the arguments (for example if you need to pass an argument that has a path with a space in it: "C:\Program Files\..."). I posted it here because, even though it may not have been the cause of your specific error case, it will hopefully help someone else experiencing this cryptic error because of Node's handling of quotes on Windows like I was encountering.
-
laconbass almost 7 yearsnode.js already makes some Black Magic and silently quotes arguments "properly". Your example should work without the undocumented option you mention, by unquoting argument inside the array.
-
Mitro over 6 yearsso is there a way to execute in a specific directory the command?
-
Alexander Mills over 6 yearseveryone who likes this answer, may also be interested in this native alternative: gist.github.com/ORESoftware/7bf225f0045b4649de6848f1ea5def4c
-
Tom over 5 yearsI was running the command as root/ with sudo so the
PATH
environment variable was not the same. Step 3 was the step that pointed this out to me. Thanks! -
Ted Nyberg over 5 yearsKey part is adding
shell: true
-
A Gupta over 5 yearsThis is called as monkey patching ! :)
-
Troncoso over 5 yearsJust to add my own experience, I was running a java process from node. This error happened to me because of quotes around the command, rather than the argument. Test with spaces in the command path and it still works without quotes
-
demisx over 5 yearsHmm... Didn't work for me. Placed it at the top of
gulpfile.js
-
Museful over 5 yearsIn Windows (7) it seems you also need to include the drive letter in the
cwd
path: 'c:/...' and not just '/...' -
Nickofthyme over 5 yearsI was able to solve my issue by passing
shell: true
to the spawn options. -
laconbass over 5 yearsWhile this may be a solution for win specific fixes, I don't see how it helps to debug the real cause of the ENOENT
-
Darius about 5 yearsReplace
console.log(arguments)
withconsole.log(JSON.stringify(arguments, null, 4))
in case of nested (non-circular) objects that you want to print -
givanse about 5 yearsDownvoted because if what you want to have is a shell then you should use
child_process.exec
or passshell: true
tospawn
. -
Alexander Mills about 5 years@givanse not necessarily true - you may want to run zsh or bash or fsh depending on what shell you want to use, and the behavior is also different
-
Matt Molnar about 5 yearsAlso, if your Node process is running inside a container like Docker, make sure the command you're trying to run has been added to the Dockerfile
-
Mathieu CAROFF almost 5 yearsI have no idea why, but the spawn call would work in the node repl without the
.cmd
, but fail in a typescript jest test. -- This error can be quite hard to figure out, this answers deserves more upvotes. -
Nick about 4 yearsWow such a simple solution and it worked for me! Everyone should try this first to see if it solves the issue.
-
laconbass almost 4 yearsAgain, related do filesystem path some way. The extension probably can't reach a path without admin permissions
-
laconbass almost 4 yearsdo you know the minimum node --version to be able to use this technique?
-
Kalle Richter almost 4 years@laconbass No. I think that's a good SO question which will be anwered within hours.
-
laconbass almost 4 yearsJust got curious. It's way better and cleaner than answer I've checked as accepted
-
MrYellow almost 4 yearsAnother issue is that
shell
MUST be a simple file path with no arguments. To setup a shell like Docker or similar where args need to be passed it must be wrapped in a proxy bash script. -
laconbass almost 4 years@MrYellow see stackoverflow.com/a/62551786/1894803
-
MrYellow almost 4 years@laconbass Yeah that overloading of
spawn
works, although the call in my case was buried within a module, made sense to use a bash script (which cleanly accepted-c command
only) to call the actual shell with arguments (innershell --foo $1 "$2"
) rather than monkey patching it deeply within the JS. -
laconbass almost 4 years@MrYellow NODE_DEBUG=child_process may also help avoiding the monkey-patching solution => stackoverflow.com/a/58474965/1894803
-
bFunc over 3 yearsThanks! This fixed my issue, no need to define cmd or path
-
Marcello de Sales over 3 yearsI was executing execa with "ab" command, but "Apache Bench" was not installed in the container... So, the first "Environment Issues" case...
-
laconbass over 3 yearsThe
.cmd
extension thing is already covered by existing answers -
Gal Bracha over 3 yearsRunning
yarn
(To install) fixed it -
laconbass almost 3 yearsYour issue seems more related to
npm
itself rather than to node'schild_process.spawn()
. And seems like a windows quirk -
John Vandivier almost 3 years
miss-installed programs
or non-interoperable installations (even when both may follow the documentation). Example: I installed python viaamazon-linux-extras
onAmazon Linux 2
but it installed to the entitypython3.8
wherePythonShell
library forNode
expected to invokepython3
. I aliased the first to the second and continued failure. Now, change the installation to directlyyum install python3
and remove the alias - no issue anymore. -
John Vandivier almost 3 years
the command does not exist
agree, or sometimes even when it does exist but only as an alias -
laconbass over 2 yearsThanks for the tip
-
Paul over 2 yearsSimply run
brew install imagemagick
-
AmiNadimi about 2 yearsThe first two lines of this answer fixed my problem!
-
Topher Fangio about 2 yearsAdding
{ shell: true }
works on MacOS as well.