8

I'm using Node's childProcess module to try and run NPM tasks.

When I do the following, everything works file:

  const child = childProcess.spawn('npm', ['run', taskName], {
    cwd: `${parentPath}/${projectId}`,
  });

However, I need to provide environment variables for the command to succeed. I tried using the env argument, like so:

  const child = childProcess.spawn('npm', ['run', taskName], {
    cwd: `${parentPath}/${projectId}`,
    env: {
      ...process.env,
      PORT: 4545,
    }
  });

When I do this, I get the following error: Uncaught Error: spawn npm ENOENT.

It turns out, I get this error regardless of what the env value is, and regardless of what the command is. For example:

  const child = childProcess.spawn('which', ['npm'], {
    cwd: `${parentPath}/${projectId}`,
    env: process.env,
  });

This code fails with Uncaught Error: spawn which ENOENT. In other words, when any value is set to env, then the spawned process fails since even built-in commands like which are unknown.

EDIT: maybe worth mentioning that I'm using Electron. I know Electron somehow fuses Node and Chromium, so maybe it's some quirk with that?

bennygenel
  • 23,896
  • 6
  • 65
  • 78
Joshua Comeau
  • 2,594
  • 24
  • 25
  • Did you try to provide the absolute path? I am not sure how it works but `ENV` contains `PWD`, so it can be confused for `spawn` when you provides other `PWD` in `ENV` (it's `__dirname` of executed Node file) than `CWD` in `spawn`. – Pawel Zentala Jun 03 '18 at 16:07
  • Hi Pawel, yeah so `parentPath` in this case uses `os.homeDir()` to get an absolute path to that directory (the variable name is confusing, sorry about that!) – Joshua Comeau Jun 04 '18 at 14:20
  • I tested the second case (`which npm`, but with `__dirname` instead `${parentPath}/${projectId}`) and it is working for me. I tested with Node v6.11.4 and v10.3.0. So probably the case is about something around this code. Could you replace this path with `__dirname`? Could you console.log `${parentPath}/${projectId}` and show me the result? – Pawel Zentala Jun 05 '18 at 11:24
  • My guess is it's something Electron based. Tried it with `__dirname`, same result. It gives me the result regardless of what the command is. even spawning `ls` without arguments or a `cwd` throws the same error, `spawn ls ENOENT`. The logged path is `/Users/joshuacomeau/work/guppy-projects/hello-world` – Joshua Comeau Jun 06 '18 at 23:19
  • Have you tried fully-qualifying the path, btw? `/usr/bin/npm`, for example (correcting for the real location). If that fails, then you're likely sandboxed (be it via SELinux constraints, or a chroot jail, or something else). – Charles Duffy Jul 16 '18 at 16:10
  • @CharlesDuffy Ah, good idea. Tried it and it succeeded in finding NPM, but failed by not being able to find Node (which makes sense to me, if the path is overwritten, that the script itself would fail) – Joshua Comeau Jul 17 '18 at 12:24
  • ...so, you should then be able to run `/usr/bin/printenv` to look at your actual environment, including the PATH, and get a more solid look at what's going on (maybe editing what that finds into the question). Or take the advice in my answer and use `/usr/bin/env` to set the `PORT` variable without changing anything else. :) – Charles Duffy Jul 17 '18 at 12:33

1 Answers1

5

You can override the PORT even without passing env, using /usr/bin/env

const child = childProcess.spawn('env', ['PORT=4545', 'npm', 'run', taskName], {
  cwd: `${parentPath}/${projectId}`,
});

If you haven't checked process.env, make sure you override PATH with a known-good value.

const child = childProcess.spawn('npm', ['run', taskName], {
  cwd: `${parentPath}/${projectId}`,
  env: {
    PATH: '/bin:/usr/bin:/usr/local/bin',
    PORT: 4545,
  }
});
Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
  • You're my absolute hero. The simple solution of just using `env` as the main command and then stringing your ENV variables and the rest of your commands was an eye opener and a lifesaver. I'd give you more bounty if I could. Well done! – Joshua Pinter Apr 19 '20 at 03:18