cli icon indicating copy to clipboard operation
cli copied to clipboard

[BUG] `TypeError: Cannot set property 'dev' of null` when using --workspace flag

Open lfowlie opened this issue 4 years ago • 34 comments

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

  1. Setup an npm project with workspaces
  2. Create a docker container according to the above specifications, with one of the commands attempting to run npm install for a specific workspace
  3. Attempt to build the container
  4. npm installs node_modules successfully but exits with error

Environment

  • OS: Debian GNU/Linux 9 (stretch)
  • Node: 14.16.1
  • npm: 7.24.2

lfowlie avatar Oct 06 '21 23:10 lfowlie

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.

niekcandaele avatar Oct 16 '21 19:10 niekcandaele

I have this same problem using [email protected] and npm@8.

Works fine with [email protected].

Pitasi avatar Oct 19 '21 08:10 Pitasi

Thanks for the comments @niekcandaele and @Pitasi. I'll try 7.18.1 and see if that works

lfowlie avatar Nov 01 '21 20:11 lfowlie

Verified that [email protected] does work, thanks!! Leaving open as this should probably be fixed for newer versions

lfowlie avatar Nov 04 '21 20:11 lfowlie

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

mlaopane avatar Dec 30 '21 23:12 mlaopane

Hitting this same issue using workspaces with [email protected] and [email protected]

npm ERR! Cannot set properties of null (setting 'dev')

chriskinsman avatar Jan 27 '22 01:01 chriskinsman

[email protected] from time to time return this error on the package adding but the next attempt is always successful.

Pavel-Husakouski avatar Jan 27 '22 15:01 Pavel-Husakouski

Is there any workaround for this issue without downgrading to npm 7.18?

dsuresh-ap avatar Jan 31 '22 22:01 dsuresh-ap

+1 any workaround for this issue?

winston0410 avatar Feb 08 '22 20:02 winston0410

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"
}

orvn avatar Feb 09 '22 21:02 orvn

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.

Pavel-Husakouski avatar Feb 11 '22 10:02 Pavel-Husakouski

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 avatar Mar 04 '22 19:03 domgenv

@domgenv npm 8.1.2 is very old; can you try with v8.5.3?

ljharb avatar Mar 04 '22 20:03 ljharb

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.

domgenv avatar Mar 04 '22 23:03 domgenv

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.

sergeyampo avatar Mar 20 '22 17:03 sergeyampo

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

dztek avatar Mar 28 '22 05:03 dztek

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

evelant avatar Apr 20 '22 21:04 evelant

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

To keep using last node version with workspaces I decided to replace npm with yarn on the project

sergeyampo avatar Apr 21 '22 13:04 sergeyampo

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.

mnapoli avatar May 02 '22 13:05 mnapoli

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.

wraithgar avatar May 03 '22 17:05 wraithgar

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 }

hitesh-sourcefuse avatar May 04 '22 07:05 hitesh-sourcefuse

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:...

shirshendubhowmick avatar May 06 '22 07:05 shirshendubhowmick

@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.

cowens-genvidtech avatar May 06 '22 16:05 cowens-genvidtech

$ npm --version
8.10.0

$ npm i -ws
npm ERR! Cannot set property 'dev' of null

mikemaccana avatar May 16 '22 13:05 mikemaccana

The problem for me, following the responses, was linking a repo with npm link

rulrok avatar May 21 '22 00:05 rulrok

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?

nlf avatar May 31 '22 16:05 nlf

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 avatar May 31 '22 17:05 nlf

@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.

ariofrio avatar Jun 02 '22 21:06 ariofrio

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 avatar Jun 02 '22 21:06 wraithgar

@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.

ariofrio avatar Jun 02 '22 21:06 ariofrio