[BUG] `TypeError: Cannot set property 'dev' of null` when using --workspace flag
Is there an existing issue for this?
- [X] I have searched the existing issues
Current Behavior
Running npm install --workspace=<workspace> is resulting in npm exiting with an errorcode and the following stack trace:
290 timing command:install Completed in 2473ms
291 verbose stack TypeError: Cannot set property 'dev' of null
291 verbose stack at calcDepFlagsStep (/usr/local/lib/node_modules/npm/node_modules/@npmcli/arborist/lib/calc-dep-flags.js:34:21)
291 verbose stack at visit (/usr/local/lib/node_modules/npm/node_modules/@npmcli/arborist/lib/calc-dep-flags.js:12:20)
291 verbose stack at visitNode (/usr/local/lib/node_modules/npm/node_modules/treeverse/lib/depth-descent.js:57:25)
291 verbose stack at next (/usr/local/lib/node_modules/npm/node_modules/treeverse/lib/depth-descent.js:44:19)
291 verbose stack at depth (/usr/local/lib/node_modules/npm/node_modules/treeverse/lib/depth-descent.js:82:10)
291 verbose stack at depth (/usr/local/lib/node_modules/npm/node_modules/treeverse/lib/depth.js:27:12)
291 verbose stack at calcDepFlags (/usr/local/lib/node_modules/npm/node_modules/@npmcli/arborist/lib/calc-dep-flags.js:10:15)
291 verbose stack at Arborist.[copyIdealToActual] (/usr/local/lib/node_modules/npm/node_modules/@npmcli/arborist/lib/arborist/reify.js:1375:7)
291 verbose stack at Arborist.reify (/usr/local/lib/node_modules/npm/node_modules/@npmcli/arborist/lib/arborist/reify.js:151:35)
291 verbose stack at async Install.install (/usr/local/lib/node_modules/npm/lib/install.js:170:5)
292 verbose cwd /usr/src
293 verbose Linux 5.10.47-linuxkit
294 verbose argv "/usr/local/bin/node" "/usr/local/bin/npm" "install" "--workspace=scheduler"
295 verbose node v14.16.1
296 verbose npm v7.24.2
297 error Cannot set property 'dev' of null
298 verbose exit 1
Dockerfile for container I'm running the command in:
FROM node:14.16.1
RUN npm install -g [email protected]
RUN mkdir -p /usr/src/
WORKDIR /usr/src
COPY ./package.json /usr/src/
COPY ./scheduler/package.json /usr/src/scheduler/
RUN npm install --workspace=scheduler
node_modules seem to successfully install but npm exits with an error code
Expected Behavior
npm install completes without raising an error
Steps To Reproduce
- Setup an npm project with workspaces
- Create a docker container according to the above specifications, with one of the commands attempting to run npm install for a specific workspace
- Attempt to build the container
- npm installs node_modules successfully but exits with error
Environment
- OS: Debian GNU/Linux 9 (stretch)
- Node: 14.16.1
- npm: 7.24.2
Had the same issue but with npm ci --only=production --workspaces.
However, the command was working locally for me. It failed inside Docker. So I compared my host environment to the Docker one and noticed the NPM versions were slightly different.
FROM node:16-alpine # Uses NPM v7.24.0
Locally I was using v7.18.1.
FROM node:16-alpine as runner
RUN npm install -g [email protected]
# < project specific stuff here >
RUN npm ci --only=production --workspaces
CMD [ "npm", "start" ]
Works :)
Hope this helps narrowing down the issue.
Thanks for the comments @niekcandaele and @Pitasi. I'll try 7.18.1 and see if that works
Verified that [email protected] does work, thanks!! Leaving open as this should probably be fixed for newer versions
I had the same issue with [email protected] and the error disappeared with [email protected].
However I managed to make it work with [email protected] by fixing my Dockerfile.
The issue came from missing workspaces package.json which were dependencies of the package I was trying to install.
In my case, given that home-ui depends on core, I did the following fixes :
Before
FROM node:16-buster
COPY package*.json ./
COPY packages/home-ui/package.json ./packages/home-ui/
RUN npm ci -w packages/home-ui
After
FROM node:16-buster
COPY package*.json ./
COPY packages/core/package.json ./packages/core/
COPY packages/home-ui/package.json ./packages/home-ui/
RUN npm ci -w packages/home-ui
Hitting this same issue using workspaces with [email protected] and [email protected]
npm ERR! Cannot set properties of null (setting 'dev')
[email protected] from time to time return this error on the package adding but the next attempt is always successful.
Is there any workaround for this issue without downgrading to npm 7.18?
+1 any workaround for this issue?
This still seems to be an issue in npm 8, so I reverted to node 16.4.2, which was the last version to ship with npm 7.18.
An alternative when installing a workspace as a dependency of another workspace is to just write the directory path into the package.json of the workspace that wants the dependency. This works with npm 8, but I opted to stay on the safe side and keep 7.18 to avoid potential future problems.
{
"dependencies": {
"@my-project/another-workspace": "file:packages/another-workspace"
}
Another similar issue with node 17.3 npm 8.3.2: Cannot set properties of null (setting 'peer')
The workaround is to delete the node_modules folder at the root package folder.
I'm on node v16.13.2 and npm 8.1.2 and I ran into this problem too. I have a monorepo with three folders: common, web, and server. The web and server both use the common folder as a dependency. Project is structured like this...
/common
/web
/server
package.json
I had to update the package.json from this...
{
"scripts": {
"install-common:server": "npm install ./common --workspace server",
"install-common:web": "npm install ./common --workspace web",
},
"workspaces": [
"common",
"server",
"web"
]
}
To this...
{
"scripts": {
"install-common:server": "cd server && npm install --save ../common",
"install-common:web": "cd web && npm install --save ../common",
},
"workspaces": [
"common",
"server",
"web"
]
}
I'm new to using workspaces, but I think this likely defeats the purpose of using workspaces since each folder will now be using it's own version of common instead of using a shared folder referenced by symlinks. But this is my workaround for now.
@domgenv npm 8.1.2 is very old; can you try with v8.5.3?
Thanks for the suggestion, @ljharb. I upgraded npm to 8.5.3 and it looks like it's still doing the same thing. I'm seeing the same thing in ovrn comment where the folder path is being removed, so the dependency is being added as file:common instead of file:../common.
I hope there will be a solution soon because this error literally shows that npm workspaces doesn't work. Only thing working for me is to downgrade npm to 7.18.1 version.
For me this works:
npm -w {ws} ci --install-peer-deps
then from root:
npm install
To make sure it's all wired up correctly:
npm ls
Also running into this bug. npm 8.7.0 crashes with npm ERR! Cannot set properties of null (setting 'dev')
Like others have said npm install -g [email protected] reverts to a version that doesn't contain this bug
Also running into this bug. npm
8.7.0crashes withnpm ERR! Cannot set properties of null (setting 'dev')Like others have said
npm install -g [email protected]reverts to a version that doesn't contain this bug
To keep using last node version with workspaces I decided to replace npm with yarn on the project
I had the same problem with this setup:
package.json
foo/
package.json
packages/
bar/
package.json
Switching to this layout solved the problem for me:
package.json
foo/
package.json
bar/
package.json
That also means that I changed foo/package.json:
"dependencies": {
- "@my-org/bar": "file:./packages/bar",
+ "@my-org/bar": "file:./bar",
...
I would conclude that NPM workspaces don't support packages that are not in the same directory.
I'm having trouble finding any comments in here that show how to reproduce this. A lot reference package.json files but don't specify what's in them.
For starters, the package specs for workspaces should not be file they should reference the version that's in the workspace. npm will use the workspace automatically if the names match.
So as an example
$ npm init -y; npm init -y -w packages/workspace-a;npm init -y -w workspace-b
$ npm install
$ $ npm ls
[email protected] /Users/wraithgar/Development/npm/scratch/ws
├── [email protected] -> ./packages/workspace-a
└── [email protected] -> ./workspace-b
$ npm i workspace-a -w workspace-b
$ $ npm ls
[email protected] /Users/wraithgar/Development/npm/scratch/ws
├── [email protected] -> ./packages/workspace-a
└─┬ [email protected] -> ./workspace-b
└── [email protected] deduped -> ./packages/workspace-a
$ cat workspace-b/package.json|grep workspace-a
"workspace-a": "^1.0.0"
This setup references workspaces at multiple directory levels, which rely one on another, without this error.
it is happening in the ".nvm/versions/node/v14.17.2/lib/node_modules/npm/node_modules/@npmcli/arborist/lib/calc-dep-flags.js" on line 34 as target is set to null
ArboristLink { name: '@services/common', packageName: 'common', location: 'a-service/node_modules/@service/common', path: '/Projects/app-api/services/a-service/node_modules/@services/common', realpath: '/Projects/app-api/services/pacakages/common', resolved: 'file:../../../pacakages/common', edgesIn: Set(1) { { a-service prod @services/common@file:../pacakages/common } }, target: null }
Problem exists with npm v8.7+ also.
What I have noticed is this happens while using npm workspaces and one of the dependency installed as file:...
@wraithgar If that is the case and workspace dependency file type references are disallowed, it should be documented. Nothing in the current NPM documentation suggests this setup would result in any kind of problem. If possible, it would be nice for a more useful error to be emitted by the NPM cli in this scenario. The current error is extremely misleading.
$ npm --version
8.10.0
$ npm i -ws
npm ERR! Cannot set property 'dev' of null
The problem for me, following the responses, was linking a repo with npm link
as @wraithgar mentioned there's no need to use file: dependency types when using workspaces, so those of you who are doing that you should change those file: references to a semver range that matches the workspace (yes, this means if you bump the version of the workspace you'll need to make sure all of its dependents get their package.json updated). after doing that, the workspace will deduplicate to the top level and everything will be using the same workspace link.
can anyone provide a minimal reproduction of this problem?
per the above linked closed issue, it seems like maybe some folks are installing a workspace as a dependency to another workspace with something like the following:
npm init -y
npm init -y -w ./pkg-a
npm init -y -w ./pkg-b
npm i ./pkg-a -w ./pkg-b
if this describes the situation any of you are in, try the last command as npm i pkg-a -w ./pkg-b without the leading ./, this will allow npm to correctly identify that your intent is to install the workspace and not to try to create another symlink
@nlf, this is occuring even when running npm install --workspace package-name, without an argument. I've come up with a minimal reproduction here: https://github.com/coldriverstudio/npm-workspace-install-bug
In case it's not clear, the intention is to download and install only packages that are recursively depended on by package-name, while skipping packages that are only depended on by other packages in the workspace.
How did you create that package-lock @ariofrio it very much does have the same root cause there. It's got "version": "file:dependency" as the version for the workspace
@wraithgar Taking a closer look, it seems that that package-lock was somehow created as I was renaming and moving the "dependency" package to "packages/greeting". I forgot to update the old name in "packages/server/package.json" and it somehow got stuck in the package-lock. npm install didn't notice there's anything wrong or that we're referencing a non-existent package, until I add "--workspace packages/server" to it. This seems like a bug in that it maybe it should have given an error (and a more descriptive one) even when --workspace is not provided!
When I fix "packages/server/package.json", delete the "package-lock.json" and re-run npm install, the error goes away.
This left me confused because it was still occuring on my Docker-based service. The problem turned out to be that I misunderstood the way the COPY directive works. I did:
COPY package.json package-lock.json packages .
However, when I log into the container, the directory structure was not what I expected:
$ ls /app
package.json
package-lock.json
package-a
package-b
package-c
...
Turns out COPY doesn't work the same way as cp when the input argument is a directory:
If <src> is a directory, the entire contents of the directory are copied, including filesystem metadata.
Note: The directory itself is not copied, just its contents.
The fix was to do this instead:
COPY package.json package-lock.json .
COPY packages packages
This is perhaps a similar failure mode as above: a non-existent workspace package directory as specified in the "package-lock.json" file. Maybe npm should check that the directory exists and give an appropriate error instead of the cryptic one it currently gives, helping people debug the problem more easily.