Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ENOENT error when loading this library #4

Closed
alcuadrado opened this issue Sep 18, 2019 · 23 comments · Fixed by #7
Closed

ENOENT error when loading this library #4

alcuadrado opened this issue Sep 18, 2019 · 23 comments · Fixed by #7

Comments

@alcuadrado
Copy link

Hi Sindre,

I've just got a bug report from one of my users that is related to this library. When you require it, it can throw an ENOENT error in this line if globalDirs.npm.packages doesn't exist.

I'm not sure if this should be considered a bug here or in global-dirs.

The stack trace of the error:

Error: ENOENT: no such file or directory, lstat '/home/billyrennekamp/GitHub.com/clovers-network/clovers-contracts/${HOME}'
    at Object.realpathSync (fs.js:1457:7)
    at Object.<anonymous> (/home/billyrennekamp/GitHub.com/clovers-network/clovers-contracts/node_modules/is-installed-globally/index.js:8:29)
    at Module._compile (internal/modules/cjs/loader.js:689:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:700:10)
    at Module.load (internal/modules/cjs/loader.js:599:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:538:12)
    at Function.Module._load (internal/modules/cjs/loader.js:530:3)
    at Module.require (internal/modules/cjs/loader.js:637:17)
    at require (internal/modules/cjs/helpers.js:22:18)
    at Object.getExecutionMode (/home/billyrennekamp/GitHub.com/clovers-network/clovers-contracts/node_modules/@nomiclabs/buidler/src/internal/core/execution-mode.ts:29:7)
@alcuadrado
Copy link
Author

Some info: I can reproduce it in my machine by installing with yarn, and running nvm use system before my app.

@alcuadrado
Copy link
Author

I could reproduce it with without yarn.

If you install the project with nvm's npm and then switch to system's node, it throws the same error.

If you install with system's npm and then switch to nvm's node, it doesn't throw.

@sindresorhus
Copy link
Owner

I just published a new version with enhanced detection: https://github.com/sindresorhus/is-installed-globally/releases/tag/v0.3.0 Could you let me know whether it has the same problem?

@alcuadrado
Copy link
Author

Thanks for the quick reply!

I'm afraid it's still present. Here's a reproduction:

pato@pmbp:iig% npm init -y
Wrote to /private/tmp/iig/package.json:

{
  "name": "iig",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}


pato@pmbp:iig% which node
/Users/pato/.nvm/versions/node/v8.16.0/bin/node
pato@pmbp:iig% npm i is-installed-globally
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN iig@1.0.0 No description
npm WARN iig@1.0.0 No repository field.

+ is-installed-globally@0.3.0
added 4 packages from 2 contributors and audited 4 packages in 1.506s
found 0 vulnerabilities

pato@pmbp:iig% nvm use system
Now using system version of node: v12.4.0 (npm v6.9.0)
pato@pmbp:iig% node -e "require('is-installed-globally')"
fs.js:126
    throw err;
    ^

Error: ENOENT: no such file or directory, lstat '/usr/local/Cellar/node/12.4.0/lib/node_modules'
    at Object.realpathSync (fs.js:1470:7)
    at Object.<anonymous> (/private/tmp/iig/node_modules/is-installed-globally/index.js:8:29)
    at Module._compile (internal/modules/cjs/loader.js:774:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:785:10)
    at Module.load (internal/modules/cjs/loader.js:641:32)
    at Function.Module._load (internal/modules/cjs/loader.js:556:12)
    at Module.require (internal/modules/cjs/loader.js:681:19)
    at require (internal/modules/cjs/helpers.js:16:16)
    at [eval]:1:1
    at Script.runInThisContext (vm.js:123:20) {
  errno: -2,
  syscall: 'lstat',
  code: 'ENOENT',
  path: '/usr/local/Cellar/node/12.4.0/lib/node_modules'
}
pato@pmbp:iig% uname -a
Darwin pmbp 18.7.0 Darwin Kernel Version 18.7.0: Tue Aug 20 16:57:14 PDT 2019; root:xnu-4903.271.2~2/RELEASE_X86_64 x86_64

@frankdilo
Copy link

I am having the same issue on macOS and managed to find out why.

/usr/local/Cellar/node/12.3.1/bin/node is the process.execPath when running np. Based on this, the global-dirs package, tries to build the node_modules directory path, guessing that it will be located at /usr/local/Cellar/node/12.3.1/lib/node_modules. This directory does not exist.

Node modules are located for my node installation (pretty recent one) at /usr/local/lib/node_modules.

Here the line where I think the error is: https://github.com/sindresorhus/global-dirs/blob/master/index.js#L46

@frankdilo
Copy link

This could be a safer approach for getting the node_modules path:

  const npmPath = require.resolve("npm");
  const nodeModulesDirectoryPath = path.resolve(npmPath, "..", "..", "..");

Happy to patch global-dirs myself if you like the approach @sindresorhus

@sindresorhus
Copy link
Owner

// @vladimyr @boneskull

@boneskull
Copy link

so the strategy of global-dirs is “guessing.”

but there are many edge cases and potential configurations. its also really difficult to test said configurations in CI, even if we knew how to arrive at them.

I wouldn’t be able to say “yes, send that PR” with any confidence that it wouldn’t break somebody else.

maybe an alternative would be providing modules like this one and global-dirs which call fs.stat to validate its assumptions. surely most users won’t need this and guessing will work for them, but for others, maybe an alternative module would be more suitable (especially if you are writing tools)

@sindresorhus
Copy link
Owner

@boneskull It's not supposed to be guessing. It tried to follow what npm/Yarn uses.

But yes, it could use some more use of fs.existsSync. We already do some of that. But really, every step in that logic should validate the assumption.

@sindresorhus
Copy link
Owner

This could be a safer approach for getting the node_modules path:

We could add it as a last effort, but the existing logic is close to what npm/Yarn uses and should be the preferred, I think.

@boneskull
Copy link

using sync APIs will be problematic depending on what’s consuming the module, of course. though perhaps it’s fine to use them unless people are asking about it.

but yeah the idea would be to validate each and every assumption.

@boneskull
Copy link

it seems like the problem is that homebrew does what homebrew does, and that’s subject to the whims of the project

@sindresorhus
Copy link
Owner

@frankdilo Would you be willing to do a PR with your approach as a backup? And maybe also more use of fs.existsSync.

@frankdilo
Copy link

@sindresorhus sure thing, will work on it soon

@vladimyr
Copy link

it seems like the problem is that homebrew does what homebrew does, and that’s subject to the whims of the project

I don't have much time atm 🏃 to go deep enough but this isn't homebrew's fault. What homebrew does is that it modifies global npmrc file which is perfectly legit: https://github.com/Homebrew/homebrew-core/blob/ac1a1e7/Formula/node.rb#L77

We could add it as a last effort, but the existing logic is close to what npm/Yarn uses and should be the preferred, I think.

...and then if that was really the case we wouldn't have trouble finding global dirs on brewed installations.

Bottom line, there is a large portion of config handling (both npm/rc & yarn) that needs to be incorporated into global-dirs in order to do it right way. You could do some guessing and try to avoid it but that will impose usage of sync methods (as already concluded) plus it is just matter of time when it will fail because at the end of the day it surely will...

@alcuadrado
Copy link
Author

I'm not an expert on how global-dirs works, but have been following some discussions there for some time, and my understanding is that giving the complexity of the task, there's always the possibility of it being wrong. It would be super useful to have a way to validate if its results are correct or not.

I'm currently using this exception as such, and have a fallback to another, less robust, detection method if this happens.

@vladimyr
Copy link

vladimyr commented Sep 23, 2019

Btw, no promises made but if you manage to give me some time window to solve it once and for all I'm willing to take a shot this weekend...

so the strategy of global-dirs is “guessing.”

but there are many edge cases and potential configurations. its also really difficult to test said configurations in CI, even if we knew how to arrive at them.

ATM, it definitely isn't something impossible to solve you just need to replicate what npm/yarn does without cutting corners (ignoring config files).

This could be a safer approach for getting the node_modules path:

  const npmPath = require.resolve("npm");
  const nodeModulesDirectoryPath = path.resolve(npmPath, "..", "..", "..");

Happy to patch global-dirs myself if you like the approach @sindresorhus

FWIW my vote goes against magic paths as temporary/interim/case-by-case solutions.

@alcuadrado That being said even if global-dirs gets properly fixed and refactored this won't necessarily fix your issue. If I read this correctly you are trying to juggle between nvm & brew installation of node?
Those two are incompatible in terms of prefix handling and sooner or later you'll end up in trouble ⚠️


UPDATE: Reason why: nvm-sh/nvm#855 homebrew sets prefix inside global npmrc while nvm does not support it meaning they can't work together ❗️

@alcuadrado
Copy link
Author

@alcuadrado That being said even if global-dirs gets properly fixed and refactored this won't necessarily fix your issue. If I read this correctly you are trying to juggle between nvm & brew installation of node?
Those two are incompatible in terms of prefix handling and sooner or later you'll end up in trouble ⚠️

That makes sense. This helps me give an explanation to our users. Thanks

@frankdilo
Copy link

I think perfect may be getting in the way of good here. For a while anyone that installed on a brew version of node super-popular libraries (such as np by @sindresorhus) that relied on global-dirs gets this unfixable error when running it.

A quick patch is in order, we can talk about fixing this for good later on, if that's even possible.

@vladimyr
Copy link

Calling it good is definitely a stretch although - when you put things in perspective (and I wasn't really aware that this prevents np from running on brewed installations) it makes sense to provide people with ugly band-aid instead of letting them suffer...

OTOH if inability to run popular/useful tools becomes the final straw forcing someone to move away from installing node with brew I wholeheartedly take that as a win because they just stopped shooting themselves in the foot. 😉

@frankdilo
Copy link

I see your point, but this is the first problem I ever had in 3 years of JS development with my brewed installation.

@sholladay
Copy link

From what I can tell, this bug is caused by these lines:
https://github.com/sindresorhus/global-dirs/blob/d6c86fc94680042cb3fa1f0fb5aefbd183f850be/index.js#L28-L31

... which were introduced in sindresorhus/global-directory#12.

Seems to me that the assumption about this path is just wrong, at least with a default setup of Homebrew/Node/npm.

@vladimyr
Copy link

vladimyr commented Nov 7, 2019

@sholladay Thanks for pointing this out, PR is out. 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants