node
node copied to clipboard
Cannot exec or spawn node, npm or yarn [node snap]
-
Version:
v14.16.0
-
Platform:
Linux fabio-XPS-15-7590 5.4.0-70-generic #78-Ubuntu SMP Fri Mar 19 13:29:52 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux
-
Subsystem:
child_process
- Distributed as: snap
What steps will reproduce the bug?
Install node snap: sudo snap install node --classic
Optional: fix permission issues https://npm.github.io/installation-setup-docs/installing/a-note-on-permissions.html
Then run the following:
const { exec } = require('child_process');
// Test
exec('echo "exec test is running"', (error, stdout, stderr) => {
if (error) {
console.error(`exec test error: ${error}`);
return;
}
console.log(`exec test stdout: ${stdout}`);
console.error(`exec test stderr: ${stderr}`);
});
// Node
exec('node -v', (error, stdout, stderr) => {
if (error) {
console.error(`exec node error: ${error}`);
return;
}
console.log(`exec node stdout: ${stdout}`);
console.error(`exec node stderr: ${stderr}`);
});
// NPM
exec('npm --version', (error, stdout, stderr) => {
if (error) {
console.error(`exec npm error: ${error}`);
return;
}
console.log(`exec npm stdout: ${stdout}`);
console.error(`exec npm stderr: ${stderr}`);
});
// Yarn
exec('yarn --version', (error, stdout, stderr) => {
if (error) {
console.error(`exec yarn error: ${error}`);
return;
}
console.log(`exec yarn stdout: ${stdout}`);
console.error(`exec yarn stderr: ${stderr}`);
});
// -------------------------------------------------------
const { spawn } = require('child_process');
// Test
const testSpawn = spawn('echo', ['"test spawn is running"']);
testSpawn.stdout.on('data', (data) => {
console.log(`spawn test stdout: ${data}`);
});
testSpawn.stderr.on('data', (data) => {
console.error(`spawn test stderr: ${data}`);
});
testSpawn.on('close', (code) => {
console.log(`spawn test child process exited with code ${code}`);
});
// Node
const nodeSpawn = spawn('node', ['-v']);
nodeSpawn.stdout.on('data', (data) => {
console.log(`spawn node stdout: ${data}`);
});
nodeSpawn.stderr.on('data', (data) => {
console.error(`spawn node stderr: ${data}`);
});
nodeSpawn.on('close', (code) => {
console.log(`spawn node child process exited with code ${code}`);
});
// NPM
const npmSpawn = spawn('npm', ['--version']);
npmSpawn.stdout.on('data', (data) => {
console.log(`spawn npm stdout: ${data}`);
});
npmSpawn.stderr.on('data', (data) => {
console.error(`spawn npm stderr: ${data}`);
});
npmSpawn.on('close', (code) => {
console.log(`spawn npm child process exited with code ${code}`);
});
// Yarn
const yarnSpawn = spawn('yarn', ['--version']);
yarnSpawn.stdout.on('data', (data) => {
console.log(`spawn yarn stdout: ${data}`);
});
yarnSpawn.stderr.on('data', (data) => {
console.error(`spawn yarn stderr: ${data}`);
});
yarnSpawn.on('close', (code) => {
console.log(`spawn yarn child process exited with code ${code}`);
});
How often does it reproduce? Is there a required condition?
It always happens to me. I think a requirement to be using node from the snap.
What is the expected behaviour?
$ node index.js
spawn test stdout: "test spawn is running"
spawn test child process exited with code 0
exec test stdout: exec test is running
exec test stderr:
exec node stdout: v14.16.0
exec node stderr:
spawn node stdout: v14.16.0
spawn node child process exited with code 0
spawn yarn stdout: 1.22.5
spawn yarn child process exited with code 0
exec yarn stdout: 1.22.5
exec yarn stderr:
exec npm stdout: 7.7.5
exec npm stderr:
spawn npm stdout: 7.7.5
spawn npm child process exited with code 0
What do you see instead?
$ node index.js
spawn test stdout: "test spawn is running"
spawn test child process exited with code 0
exec test stdout: exec test is running
exec test stderr:
exec node stdout:
exec node stderr:
spawn node child process exited with code 0
spawn yarn child process exited with code 1
exec yarn error: Error: Command failed: yarn --version
exec npm stdout:
exec npm stderr:
spawn npm child process exited with code 0
The output of node and npm commands is empty, while yarn fails.
However, running each of those commands from the terminal works correctly:
$ node -v
v14.16.0
$ npm --version
7.7.5
$ yarn --version
1.22.5
Additional information
Running a command like which npm
returns the correct binary path both from the terminal and from the script. I also attempted to write the full path in the script, instead of the command, (e.g. /home/fabio/.npm-global/bin/npm
) but nothing changes.
The node binary is provided by the node snap. However, I could not find clear issues in the logs. Also npm and yarn are provided in the snap, but I installed them globally under /home/fabio/.npm-global
.
✅ I'm willing to help with debugging and getting this solved. 👨💻
I mentioned this issue in the snap forum, so we might receive some special assistance from snap experts: https://forum.snapcraft.io/t/node-snap-issues-with-exec-of-npm-node-yarn/23635
Can you try to run the following commands in your terminal:
/bin/sh -c 'node -v'
/bin/sh -c 'npm --version'
/bin/sh -c 'yarn --version'
Sure, here you are:
$ /bin/sh -c 'node -v'
v14.16.0
$ /bin/sh -c 'npm --version'
7.7.5
$ /bin/sh -c 'yarn --version'
1.22.5
Possibly related issues:
- https://bugs.launchpad.net/ubuntu/+source/snapd/+bug/1849753
- https://github.com/snapcore/snapd/pull/10029
https://github.com/microsoft/vscode-vsce/issues/341 was recently closed, apparently owing to this or a similar problem with child processes. Mentioning here.
Hi! We installed Node.js via snap store and tried to use exec
and spawn
functions in the VS Code extension environment. In the test extension we could also reproduce the same incorrect behavior as described in this issue. The functions for spawning child processes skip the execution of npm and CLI commands (based on Node.js scripts) and return just an empty result or an error.
I am getting same error when doing spawn('yarn build')
. code: 'ENOENT'. And getting same error on running any node binaries (webpack, npm etc). System commands (like curl, zip) are working fine.
I tried doing which yarn
and which node
, yarn is picked from some tmp file, and node is also running from tmp yarn folder.
When I run the script directly (instead of via yarn), it returns the node inside the nvm directory path, but still not working.
Interestingly which yarn
and which node
are working fine.
I looked into this.
EDIT: Correction:
node cannot run snap
due to sandbox limitations. This blocks node from executing some snap programs as children.
on the other hand, running node in the true path (in my case /snap/node/6694/bin/node currently) will work.
causing things like a npm version check to work like this (as long as snap is installed, in which case "which" command is also present):
execSync(process.execPath + ' $(which npm) --version').toString().trim()
(returns the correct 8.19.2 in my case)
otherwise the command execSync('npm --version')
will return an empty string, because "snap" just terminates itself before printing anything.
================== Edit End ========= as noticed, node cannot spawn a child of any given snap program. This is caused by the "symlink" structure of the bin files in /snap/bin
ll /snap/bin
reveals that all of those link to /usr/bin/snap in one way or another. I have no idea how on earth the bash knows how to execute them. I guess there is an env variable which does contain this info, mapping the execution of the snap bin to snap run [bin-name]
but this means, whenever a which [snap-program-name]
resolves to /snap/bin/[prog-name]
it must be run snap run [name]
instead of calling it from terminal directly.
The bash seems to notice the weird symlink, and knows what to do. But node exec does not. (understandable, i have no idea either xD)
Anyway. There should be a solution to this.
@Bloodiko great work looking into this! :blush:
In the meanwhile the following workaround should help (works on Ubuntu 22.04):
for cmd in node npm yarn; do
mkdir -p ~/bin
cat > "$HOME/bin/$cmd" << EOF
#!/bin/bash
# https://github.com/nodejs/node/issues/37982
/snap/bin/$cmd "\$@" > >(cat) 2> >(cat >&2)
EOF
chmod +x "$HOME/bin/$cmd"
done
I'll go ahead and close this because it's a snap sandbox restriction, not an issue with node itself. If the restriction is a problem for you, you should report it to the maintainers of the snap package.