Node: Spawn is ignoring all environment variables including PATH.

Created on 12 May 2017  路  6Comments  路  Source: nodejs/node

Version: output of node -v
Platform: output of uname -a (UNIX), or version and 32 or 64-bit (Windows)
Subsystem: if known, please specify affected core module name

If possible, please provide code that demonstrates the problem, keeping it as
simple and free of external dependencies as you are able.
-->

  • Version: v6.9.2, v6.10.3, v7.10.0
  • Platform: Linux 3.10.0-327.13.1.el7.x86_64 #1 SMP Thu Mar 31 16:04:38 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux (Centos 7)
  • Subsystem: Using nvm


So I use nvm since I have many node projects, which many have different versions. Everything has been going well until... I needed to use spawn. Node is refusing to work with spawn. It is as if node was never installed. So I tried exec, and exec can find the version of node I am using and it works as expected. Spawn on the other hand is throwing errors. It fails to include environment variables. I seriously shouldn't have to include environment variables for node. It should just use my existing ones.

console.log('version', require('child_process').execSync('node --version').toString()); works as expected

require('child_process').spawn('node', ['--version'], {stdio: 'inherit'}); fails horribly

child_process question

Most helpful comment

Above is expected and documented behaviour. default value for env: is env: process.env, if you provide your own env, you chould clone process.env and add/delete any that you want to add/delete.

If you wonder why, ask yourself how you would delete a env var during spawn that you didn't want passed from the parent process to its child.

All 6 comments

I don't like this solution, but this is how you get it working. Why does the other child_process methods have the environment variable PATH included, but spawn does not???

require('child_process').spawn('node', ['--version'], {
    cwd: process.cwd(),
    env: {
        PATH: process.env.PATH
    },
    stdio: 'inherit'
});

Did you try adding shell: true to your spawn() options instead?

Also,

node -e 'require(`child_process`).spawn(`node`, [`-pe`, `process.env.PATH`], {stdio:`inherit`})'

prints my $PATH just fine.

Hmm something interesting is going on. But the behavior still doesn't seem right, however it could be intended.

require('child_process').spawn('node', ['-pe', 'process.env.PATH'], {
    cwd: process.cwd() + '/backend',
    stdio: 'inherit'
});

Prints my path as expected. however this:

require('child_process').spawn('node', ['-pe', 'process.env.PATH'], {
    cwd: process.cwd() + '/backend',
    env: {
        NODE_CONFIG_DIR: process.cwd() + '/config'
    },
    stdio: 'inherit',
    shell: true // doesn't matter if shell: true is here or not.
});

PATH is undefined...

This doesn't seem right that it would clear all the env variables when you provide an env property. If this is the case, then without having to add many environment variables to env obj, how can I just change one then?

Above is expected and documented behaviour. default value for env: is env: process.env, if you provide your own env, you chould clone process.env and add/delete any that you want to add/delete.

If you wonder why, ask yourself how you would delete a env var during spawn that you didn't want passed from the parent process to its child.

I think I found the answer, it wasn't obvious when I first read the docs.

_From Node Core Documentation_

A third argument may be used to specify additional options, with these defaults:

const defaults = {
  cwd: undefined,
  env: process.env
};

Use cwd to specify the working directory from which the process is spawned. If not given, the default is to inherit the current working directory.

Use env to specify environment variables that will be visible to the new process, the default is process.env.

Thanks for your help. Looks like all I have to do is clone process.env and then change the environment variable I want. It makes sense to why they would want spawn to work this way.

Update: @sam-github I didn't see your comment as I was posting this. Thanks :)

Another option is to use env as the command name followed by your actual commands:

require('child_process').spawn('env', ['node', '--version'], {stdio: 'inherit'})

I found this actually worked much better than doing something like:

require('child_process').spawn('node', ['--version'], {stdio: 'inherit', env: Object.assign(process.env, {MYENV: 1})})

Found it over here.

Was this page helpful?
0 / 5 - 0 ratings