Nvm: bashrc NVM EACCES: permission denied upon switching user

Created on 10 Feb 2018  路  15Comments  路  Source: nvm-sh/nvm

  • Operating system and version:
    Red Hat Enterprise Linux Server release 6.9

  • Summary:
    I have nvm installed for 'app' user, and whenever I switch from my current user to app user (from any other user's home dir) during .bashrc export, this error shows up.
    I added set -x to nvm.sh and found that it is failing while executing npm config --loglevel=warn get prefix

Error: EACCES: permission denied, scandir '/home/someuser'
Unhandled rejection TypeError: Cannot read property 'get' of undefined
    at errorHandler (/home/app/.nvm/versions/node/v8.9.4/lib/node_modules/npm/lib/utils/error-handler.js:205:18)
    at /home/app/.nvm/versions/node/v8.9.4/lib/node_modules/npm/bin/npm-cli.js:83:20
    at cb (/home/app/.nvm/versions/node/v8.9.4/lib/node_modules/npm/lib/npm.js:224:22)
    at /home/app/.nvm/versions/node/v8.9.4/lib/node_modules/npm/lib/npm.js:262:24
    at /home/app/.nvm/versions/node/v8.9.4/lib/node_modules/npm/lib/config/core.js:81:7
    at Array.forEach (<anonymous>)
    at /home/app/.nvm/versions/node/v8.9.4/lib/node_modules/npm/lib/config/core.js:80:13
    at f (/home/app/.nvm/versions/node/v8.9.4/lib/node_modules/npm/node_modules/once/once.js:25:25)
    at /home/app/.nvm/versions/node/v8.9.4/lib/node_modules/npm/lib/config/core.js:110:20
    at tryCatcher (/home/app/.nvm/versions/node/v8.9.4/lib/node_modules/npm/node_modules/bluebird/js/release/util.js:16:23)
    at Promise._settlePromiseFromHandler (/home/app/.nvm/versions/node/v8.9.4/lib/node_modules/npm/node_modules/bluebird/js/release/promise.js:512:31)
    at Promise._settlePromise (/home/app/.nvm/versions/node/v8.9.4/lib/node_modules/npm/node_modules/bluebird/js/release/promise.js:569:18)
    at Promise._settlePromise0 (/home/app/.nvm/versions/node/v8.9.4/lib/node_modules/npm/node_modules/bluebird/js/release/promise.js:614:10)
    at Promise._settlePromises (/home/app/.nvm/versions/node/v8.9.4/lib/node_modules/npm/node_modules/bluebird/js/release/promise.js:689:18)
    at Async._drainQueue (/home/app/.nvm/versions/node/v8.9.4/lib/node_modules/npm/node_modules/bluebird/js/release/async.js:133:16)
    at Async._drainQueues (/home/app/.nvm/versions/node/v8.9.4/lib/node_modules/npm/node_modules/bluebird/js/release/async.js:143:10)

TypeError: Cannot read property 'loaded' of undefined
    at process.<anonymous> (/home/app/.nvm/versions/node/v8.9.4/lib/node_modules/npm/lib/utils/error-handler.js:40:18)
    at emitOne (events.js:116:13)
    at process.emit (events.js:211:7)
/home/app/.nvm/versions/node/v8.9.4/lib/node_modules/npm/lib/utils/error-handler.js:205
  if (npm.config.get('json')) {
                 ^

TypeError: Cannot read property 'get' of undefined
    at process.errorHandler (/home/app/.nvm/versions/node/v8.9.4/lib/node_modules/npm/lib/utils/error-handler.js:205:18)
    at emitOne (events.js:116:13)
    at process.emit (events.js:211:7)
    at process._fatalException (bootstrap_node.js:374:26)
  • nvm debug output:

nvm --version: v0.33.8
$SHELL: /bin/bash
$HOME: /home/app
$NVM_DIR: '$HOME/.nvm'
$PREFIX: ''
$NPM_CONFIG_PREFIX: ''
$NVM_NODEJS_ORG_MIRROR: ''
$NVM_IOJS_ORG_MIRROR: ''
shell version: 'GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)'
uname -a: 'Linux 2.6.32-696.18.7.el6.x86_64 #1 SMP Thu Dec 28 20:15:47 EST 2017 x86_64 x86_64 x86_64 GNU/Linux'
OS version:
curl: /usr/bin/curl, curl 7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.27.1 zlib/1.2.3 libidn/1.18 libssh2/1.4.2
wget: /usr/bin/wget, GNU Wget 1.12 built on linux-gnu.
git: /usr/bin/git, git version 1.7.1
grep: /bin/grep, grep (GNU grep) 2.20
awk: /bin/awk, GNU Awk 3.1.7
sed: /bin/sed, GNU sed version 4.2.1
cut: /bin/cut, cut (GNU coreutils) 8.4
basename: /bin/basename, basename (GNU coreutils) 8.4
rm: /bin/rm, rm (GNU coreutils) 8.4
mkdir: /bin/mkdir, mkdir (GNU coreutils) 8.4
xargs: /usr/bin/xargs, xargs (GNU findutils) 4.4.2
nvm current: none
which node: which: no node in (/sbin:/bin:/usr/sbin:/usr/bin)
which iojs: which: no iojs in (/sbin:/bin:/usr/sbin:/usr/bin)
which npm: which: no npm in (/sbin:/bin:/usr/sbin:/usr/bin)
npm config get prefix: bash: npm: command not found
npm root -g: bash: npm: command not found

  • nvm debug output after sourcing .bashrc again from app user's home directory:

nvm --version: v0.33.8
$SHELL: /bin/bash
$HOME: /home/app
$NVM_DIR: '$HOME/.nvm'
$PREFIX: ''
$NPM_CONFIG_PREFIX: ''
$NVM_NODEJS_ORG_MIRROR: ''
$NVM_IOJS_ORG_MIRROR: ''
shell version: 'GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)'
uname -a: 'Linux 2.6.32-696.18.7.el6.x86_64 #1 SMP Thu Dec 28 20:15:47 EST 2017 x86_64 x86_64 x86_64 GNU/Linux'
OS version:
curl: /usr/bin/curl, curl 7.19.7 (x86_64-redhat-linux-gnu) libcurl/7.19.7 NSS/3.27.1 zlib/1.2.3 libidn/1.18 libssh2/1.4.2
wget: /usr/bin/wget, GNU Wget 1.12 built on linux-gnu.
git: /usr/bin/git, git version 1.7.1
grep: /bin/grep, grep (GNU grep) 2.20
awk: /bin/awk, GNU Awk 3.1.7
sed: /bin/sed, GNU sed version 4.2.1
cut: /bin/cut, cut (GNU coreutils) 8.4
basename: /bin/basename, basename (GNU coreutils) 8.4
rm: /bin/rm, rm (GNU coreutils) 8.4
mkdir: /bin/mkdir, mkdir (GNU coreutils) 8.4
xargs: /usr/bin/xargs, xargs (GNU findutils) 4.4.2
nvm current: v8.9.4
which node: $NVM_DIR/versions/node/v8.9.4/bin/node
which iojs: which: no iojs in ($NVM_DIR/versions/node/v8.9.4/bin:/sbin:/bin:/usr/sbin:/usr/bin)
which npm: $NVM_DIR/versions/node/v8.9.4/bin/npm
npm config get prefix: $NVM_DIR/versions/node/v8.9.4
npm root -g: $NVM_DIR/versions/node/v8.9.4/lib/node_modules

  • nvm ls output:

->       v8.9.4
default -> 8.9.4 (-> v8.9.4)
serverless-version -> 8.9.4 (-> v8.9.4)
node -> stable (-> v8.9.4) (default)
stable -> 8.9 (-> v8.9.4) (default)
iojs -> N/A (default)
lts/* -> lts/carbon (-> v8.9.4)
lts/argon -> v4.8.7 (-> N/A)
lts/boron -> v6.12.3 (-> N/A)
lts/carbon -> v8.9.4

  • How did you install nvm? (e.g. install script in readme, homebrew):

  • What steps did you perform?

  • What happened?

  • What did you expect to happen?

  • Is there anything in any of your profile files (.bashrc, .bash_profile, .zshrc, etc) that modifies the PATH?

export NVM_DIR="/home/app/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"  # This loads nvm bash_completion

  • If you are having installation issues, or getting "N/A", what does curl -I --compressed -v https://nodejs.org/dist/ print out?


root / multiuser issues

Most helpful comment

I was struggling to find a fix for this error, but as @ljharb mentionned, you should cd ~ BEFORE the nvm scripts run. So change the .bashrc file to include a cd ~ before:

export NVM_DIR="/home/app/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"  # This loads nvm bash_completion

All 15 comments

nvm is per-user; it must be installed and used entirely within the same user account (or, separately in each user account you want to have nvm available).

Separately, whenever you switch from user A to user B, you should ensure you're cdd into user B's home directory.

I think it seems there is an underlying method which appears to be scanning the dir from where you are sudo'ing from. It should always scan the NVM_DIR.

@nareshku whenever nvm.sh is sourced, it looks for a .nvmrc file in the current directory, recursively upwards. This is by design.

I was struggling to find a fix for this error, but as @ljharb mentionned, you should cd ~ BEFORE the nvm scripts run. So change the .bashrc file to include a cd ~ before:

export NVM_DIR="/home/app/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"  # This loads nvm bash_completion

Alternatively, cd into the user's $HOME prior to su-ing to that user.

Closing, since this seems answered.

I agree with some commentators above.
We do not need multiple installations of nvm.
Not that I can think of.
What if I spawn a new shell inside /var/log ?
IMHO walking recursively does not make sense. It isn't .editorconfig were nesting would make sense.
It put's itself into $HOME/.nvm and that is where it should look for the configuration.
It is not like it will put itself anywhere else, or if it does it wouldn't necessrily be usefull.

Currently we are installing nvm for a particular user and changing to the user causes errors on the shell, it remains operational and nvm is usable but not appropriate.
Especially considering that the home-directory we are sudoing from does not allow the user with nvm to read from.

Other case would be that a CI might need to use a different version of node, than is provided by system.
These shells could be spawned in a completely unrelated directory to $HOME.
Reproducability independend of system-state and no errors like these are a big plus.

Addendum:
I also found that $OLD_PWD plays a role here, so
sudo -su nvmuser "cd $HOME && nvm list" will behave awkwardly. but
sudo -su nvmuser "cd $HOME && cd somedirinside$HOME && nvm list" will be fine.
Tested with executing the commands separatley on an interactive shell though.

I'm on an ec2 instance, with a jenkins user. Jenkins has nvm installed in it's ~ (var/lib/jenkins). We ssh in, then sudo su jenkins and get the error as originally stated in the issue.

I think this is a subtlety of the way sudo su <user> works with .bash_profile. Adding pwd to .bash_profile confirms that the cwd hasn't yet changed to the new $HOME:

pwd
cd ~
pwd

# load nvm
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && source "$NVM_DIR/nvm.sh"

results:

$ sudo su jenkins
/home/ec2-user
/var/lib/jenkins

Because of the way sudo su works, and _when_ it changes directories to the new $HOME, simply loading nvm.sh in bash_profile isn't going to work.

Sure, adding a cd ~ to the startup script before sourcing nvm.sh _works_. But that leaves me pretty uncertain about adding a cd to my .bash_profile won't cause unexpected confusion or issues down the road. (edit: as expected, this caused a bunch of chaos, see update at the end)

The following ways of switching users all show the same results:

 sudo su jenkins
 sudo -su jenkins
 sudo -u jenkins bash
 sudo -u jenkins bash -l

Isn't this what the NVM_DIR variable would be used for?

update:

As expected, just running cd $HOME in the middle of bash_profile wrecked a bunch of our Jenkins jobs. The jobs which broke have a (surprise!) source ~/.bash_profile at the beginning. The short term fix was:

# .bash_profile
pushd $HOME
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && source "$NVM_DIR/nvm.sh"
popd

@robacarp i'd expect cd $HOME, but if that doesn't work, you might have to hardcode it.

Alternatively you can set NVM_DIR explicitly; but if HOME is set correctly, then it will be as well.

@ljharb $HOME does work and is correct at that point, but that's not a big surprise because I think ~ is just shorthand for $HOME (I could be wrong about that).

Should it be sufficient to set NVM_HOME without explicitly cd $HOME before sourcing nvm.sh? It's entirely possible that there is something else going on, and if so I'd like to identify and fix it.

Thanks for looking

I think you'll always want to cd $HOME (~ is often equivalent, but not always) after su-ing to a new user.

Using the -l switch will prevent this, so with su -l you can also use ~ and $HOME interchangeably again.

Should be able to switch into the target user's home directory with sudo su - jenkins.

I think you'll always want to cd $HOME (~ is often equivalent, but not always) after su-ing to a new user.

Not always.
As our team have 4 servers, and use a common Apple Script like below to run command on 4 servers at the same time.

 repeat with i from 1 to count of commands
  tell session i of current tab of current window
   write text (action of item i of commands)
  end tell
 end repeat

if one of those server auto change to $HOME and others not, it will not work.

No, we don't want to install node on all servers.
We commonly use sudo su username to change user, sudo su username -l is ok, but if any of us forget it, it will be error.

So why don't use $NVM_DIR or $HOME or ~ or anything but use pwd to get .nvmrc?

I think this has to be fixed from the script itself, not by users making workarounds.

The issue happens in this command:

NVM_NPM_PREFIX=$(npm config --loglevel=warn get prefix)

I did an awful fix in the script:

cd $NVM_DIR
NVM_NPM_PREFIX=$(npm config --loglevel=warn get prefix)
cd -

Bash scripting isn't my strong. Can someone come up with a way of running that command from NVM_DIR without having to cd into it from the main script? I think if we cd in the main script, it could cause issues because the script is sourced. Maybe a child process that returns that output, or are those sourced too?

UPDATE:
This one is working right now

NVM_NPM_PREFIX=$(cd $NVM_DIR && npm config --loglevel=warn get prefix)

The issue with that is that the config call needs to happen in the user鈥檚 current directory always, since that鈥檚 what affects npm calls.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

serbiant picture serbiant  路  4Comments

danielepolencic picture danielepolencic  路  4Comments

swateek picture swateek  路  3Comments

goalidea picture goalidea  路  3Comments

nickngqs picture nickngqs  路  3Comments