Description
I've a few project folders linked globally to /usr/local/lib/node_modules
(hereafter referred to as $NPM
). Some of the links point to projects whose node_modules
is a symlink back to $NPM
. Running npm --global upgrade
causes a stack overflow:
(Click to show contents of ~/.npm/_logs/2020-07-23T01_44_06_392Z-debug.log
)
0 info it worked if it ends with ok
1 verbose cli [
1 verbose cli '/usr/local/Cellar/node/14.5.0/bin/node',
1 verbose cli '/usr/local/bin/npm',
1 verbose cli '--global',
1 verbose cli 'upgrade',
1 verbose cli 'c8',
1 verbose cli 'cson',
1 verbose cli 'electron',
1 verbose cli 'jsdoc',
1 verbose cli 'jsvu',
1 verbose cli 'npm',
1 verbose cli 'rollup',
1 verbose cli 'typescript'
1 verbose cli ]
2 info using npm@6.14.5
3 info using node@v14.5.0
4 verbose npm-session 693c3b480696055c
5 verbose update computing outdated modules to update
6 verbose stack RangeError: Maximum call stack size exceeded
6 verbose stack at validate (/usr/local/lib/node_modules/npm/node_modules/aproba/index.js:25:19)
6 verbose stack at flatNameFromTree (/usr/local/lib/node_modules/npm/lib/install/flatten-tree.js:37:3)
6 verbose stack at flatNameFromTree (/usr/local/lib/node_modules/npm/lib/install/flatten-tree.js:39:14)
6 verbose stack at flatNameFromTree (/usr/local/lib/node_modules/npm/lib/install/flatten-tree.js:39:14)
6 verbose stack at flatNameFromTree (/usr/local/lib/node_modules/npm/lib/install/flatten-tree.js:39:14)
6 verbose stack at flatNameFromTree (/usr/local/lib/node_modules/npm/lib/install/flatten-tree.js:39:14)
6 verbose stack at flatNameFromTree (/usr/local/lib/node_modules/npm/lib/install/flatten-tree.js:39:14)
6 verbose stack at flatNameFromTree (/usr/local/lib/node_modules/npm/lib/install/flatten-tree.js:39:14)
6 verbose stack at flatNameFromTree (/usr/local/lib/node_modules/npm/lib/install/flatten-tree.js:39:14)
6 verbose stack at flatNameFromTree (/usr/local/lib/node_modules/npm/lib/install/flatten-tree.js:39:14)
6 verbose stack at flatNameFromTree (/usr/local/lib/node_modules/npm/lib/install/flatten-tree.js:39:14)
6 verbose stack at flatNameFromTree (/usr/local/lib/node_modules/npm/lib/install/flatten-tree.js:39:14)
6 verbose stack at flatNameFromTree (/usr/local/lib/node_modules/npm/lib/install/flatten-tree.js:39:14)
6 verbose stack at flatNameFromTree (/usr/local/lib/node_modules/npm/lib/install/flatten-tree.js:39:14)
6 verbose stack at flatNameFromTree (/usr/local/lib/node_modules/npm/lib/install/flatten-tree.js:39:14)
6 verbose stack at flatNameFromTree (/usr/local/lib/node_modules/npm/lib/install/flatten-tree.js:39:14)
7 verbose cwd /Users/john/Labs/Mono
8 verbose Darwin 17.7.0
9 verbose argv "/usr/local/Cellar/node/14.5.0/bin/node" "/usr/local/bin/npm" "--global" "upgrade" "c8" "cson" "electron" "jsdoc" "jsvu" "npm" "rollup" "typescript"
10 verbose node v14.5.0
11 verbose npm v6.14.5
12 error Maximum call stack size exceeded
13 verbose exit [ 1, true ]
Environment
My directory structures are laid out like this:
λ tree $NPM ~/Labs/JG/node_modules
/usr/local/lib/node_modules
├── @alhadis -> /Users/john/Labs/JG/node_modules/@alhadis
├── jg -> /Users/john/Labs/JG
└── vtt -> /Users/john/Labs/VTT
/Users/john/Labs/JG/node_modules
├── @alhadis
│ └── eslint-config -> ../../eslint
├── alhadis.utils -> ../../Utils
├── babel-eslint -> /usr/local/lib/node_modules/babel-eslint
├── eslint-plugin-import -> /usr/local/lib/node_modules/eslint-plugin-import
└── get-options -> ../../GetOptions
My ~/.npmrc
file is temporarily moved to /tmp
each time I run npm
globally (see #1346 for reasons why).
When / where
When running npm -g upgrade
or npm -g outdated
. Other subcommands are probably affected, but I only use symlinks to simplify management of globally-installed modules/projects.
Note that these symlinks were not produced by npm link
, but rather ln -s
. In all honesty, I'm not sure I get the point of npm link
…
Expected behaviour
NPM should keep track of directories it's already scanned, including those stipulated by the working directory and NPM's --global
switch.
Actual behaviour
The flatNameFromTree
function doesn't track resolved paths it traverses during recursion, inevitably resulting in a stack overflow:
RangeError: Maximum call stack size exceeded
at validate (/usr/local/lib/node_modules/npm/node_modules/aproba/index.js:25:19)
at flatNameFromTree (/usr/local/lib/node_modules/npm/lib/install/flatten-tree.js:37:3)
at flatNameFromTree (/usr/local/lib/node_modules/npm/lib/install/flatten-tree.js:39:14)
at flatNameFromTree (/usr/local/lib/node_modules/npm/lib/install/flatten-tree.js:39:14)
at flatNameFromTree (/usr/local/lib/node_modules/npm/lib/install/flatten-tree.js:39:14)
…
The problem disappears if I move symlinked entries out of $NPM
to /tmp
before running npm
.
Steps to reproduce
Hopefully self-explanatory, but if the exact structure is needed, well… this should more-or-less establish the basic layout.
cd && rm -rf /tmp/dummy-project-directory && mkdir $_ && cd $_
git clone --depth=1 https://github.com/Alhadis/Utils.git alhadis.utils
git clone --depth=1 https://github.com/Alhadis/JG.git jg
git clone --depth=1 https://github.com/Alhadis/VTT.git vtt
(cd alhadis.utils && ln -s "$OLDPWD/jg/node_modules" .)
mkdir jg/node_modules && cd $_
mkdir \@alhadis && ln -s ../../eslint "$_/eslint-config" && ln -s ../../alhadis.utils .
cd "`npm root -g`" && mv -i "$OLDPWD"/{jg,vtt} . && ln -s "$OLDPWD/jg/node_modules/@alhadis" \@alhadis
npm --global outdated
Sidenotes you probably don't care about:
- I haven't actually tested the code above, since it's intended to be illustrative rather than informative.
- Some of these projects are unfinished, hence the use of
git clone
instead ofnpm install
.