Unable to uninstall a custom node

When I tried to uninstall a node, I got errors like this

$ npm uninstall my_proj
npm WARN checkPermissions Missing write access to /Users/me/.node-red/node_modules/my_proj
npm ERR! code ENOENT
npm ERR! syscall access
npm ERR! path /Users/me/.node-red/node_modules/my_proj
npm ERR! errno -2
npm ERR! enoent ENOENT: no such file or directory, access '/Users/me/.node-red/node_modules/my_proj'
npm ERR! enoent This is related to npm not being able to find a file.
npm ERR! enoent 

npm ERR! A complete log of this run can be found in:
npm ERR!     /Users/me/.npm/_logs/2021-10-08T02_02_09_670Z-debug.log

The complete debug log looks like this

0 info it worked if it ends with ok
1 verbose cli [
1 verbose cli   '/usr/local/Cellar/node@14/14.17.6/bin/node',
1 verbose cli   '/usr/local/opt/node@14/bin/npm',
1 verbose cli   'uninstall',
1 verbose cli   'my_proj'
1 verbose cli ]
2 info using npm@6.14.15
3 info using node@v14.17.6
4 verbose npm-session 15b827f66a6db334
5 silly install loadCurrentTree
6 silly install readLocalPackageData
7 timing stage:loadCurrentTree Completed in 265ms
8 silly install loadIdealTree
9 silly install cloneCurrentTreeToIdealTree
10 timing stage:loadIdealTree:cloneCurrentTree Completed in 2ms
11 silly install loadShrinkwrap
12 timing stage:loadIdealTree:loadShrinkwrap Completed in 143ms
13 silly uninstall loadAllDepsIntoIdealTree
14 silly install loadAllDepsIntoIdealTree
15 timing stage:loadIdealTree:loadAllDepsIntoIdealTree Completed in 111ms
16 timing stage:loadIdealTree Completed in 291ms
17 silly currentTree node-red-project@0.0.1
17 silly currentTree ├── @protobufjs/aspromise@1.1.2
17 silly currentTree ├── @protobufjs/base64@1.1.2
17 silly currentTree ├── @protobufjs/codegen@2.0.4

......

23 silly saveTree │ │   ├── @protobufjs/utf8@1.1.0
23 silly saveTree │ │   ├── @types/long@4.0.1
23 silly saveTree │ │   └── long@4.0.0
23 silly saveTree │ ├─┬ alert@5.0.10
23 silly saveTree │ │ └── is-program-installed@2.2.0
23 silly saveTree │ ├── async@1.5.2
23 silly saveTree │ ├── google-protobuf@3.17.3
23 silly saveTree │ ├── lodash@4.17.21
23 silly saveTree │ └── minimist@1.2.5
23 silly saveTree ├── my_other_proj@1.0.0
23 silly saveTree └─┬ select_wobj_by_id@1.0.0
23 silly saveTree   └─┬ alert@5.0.10
23 silly saveTree     └── is-program-installed@2.2.0
24 verbose stack Error: ENOENT: no such file or directory, access '/Users/me/.node-red/node_modules/my_proj'
25 verbose cwd /Users/me/.node-red
26 verbose Darwin 20.6.0
27 verbose argv "/usr/local/Cellar/node@14/14.17.6/bin/node" "/usr/local/opt/node@14/bin/npm" "uninstall" "my_proj"
28 verbose node v14.17.6
29 verbose npm  v6.14.15
30 error code ENOENT
31 error syscall access
32 error path /Users/me/.node-red/node_modules/my_proj
33 error errno -2
34 error enoent ENOENT: no such file or directory, access '/Users/me/.node-red/node_modules/my_proj'
35 error enoent This is related to npm not being able to find a file.
36 verbose exit [ -2, true ]

While it says no such file or directory, I do have it on the file system.

$ stat /Users/me/.node-red/node_modules/my_proj
16777221 21351017 lrwxr-xr-x 1 me myoffice\Domain Users 0 68 "Sep 28 16:16:33 2021" "Sep 28 16:16:33 2021" "Sep 28 16:16:33 2021" "Sep 28 16:16:33 2021" 4096 0 0 /Users/me/.node-red/node_modules/my_proj

The only workaround I found was to manually delete that symlink /Users/me/.node-red/node_modules/my_proj. Then uninstall works

$ npm uninstall my_proj
audited 202 packages in 2.01s

5 packages are looking for funding
  run `npm fund` for details

found 5 high severity vulnerabilities
  run `npm audit fix` to fix them, or `npm audit` for details

What am I missing?

We’re you in the .node-red directory when you ran the uninstall command?

Yes I think so, I was under ~/.node-red

How did you install my_proj?

Well, I did it through Python

import os.path
import subprocess as sbp

cmd = ['npm', 'install', '/path/to/my_proj']
sbp.run(cmd, check=True, shell=False, stdout=sbp.PIPE, stderr=sbp.PIPE, cwd=os.path.expanduser('~/.node-red'))

@Colin

I set the current working directory to the correct node-red directory when running the command in the child process. This should work the same way as

cd ~/.node-red
npm install /path/to/my_proj

Was the python command running as the same user as node-red and the command line you have been using?

If you install it again (using the command line) are you then able to uninstall using the command line?

@Colin

I finally found the cause of this problem:

I manually removed the source folder of ANOTHER node without npm-uninstall it first, possibly combined with the fact that the node-red server was still on.

This actually prevented me from further uninstalling ANY node.

My guesses are

  • The node uninstall logic checks whether the node is still used by any loaded flows before removal.
  • If there are flows still using the nodes, then I would hit the permission problem.

So I'd love to validate with people here the following assumptions:

  • The only safe way to remove node is to use the node palette menu on the Node-RED panel
  • If we'd love to automate uninstalling nodes, then we have to clean up all the relevant flows first, making sure no flows are still using the nodes.
  • For a CI system, which potentially creates/removes nodes on the fly, it'd better use a specific flow to host all the nodes to minimize troubles.

Thanks!

Npm from the command line doesn't know anything about node red flows.

There are two safe ways to add/remove nodes, one is via the command line npm and the other is the palette manager (which uses npm behind the scenes). If you do it from the command line then you need to restart node red before it will see the changes.

If you do that, then the next time you run an npm command it will try to re install the missing node. That may be what was causing the errors.