Skip to content

pnpm link on macOS broken #9066

@LeviticusMB

Description

@LeviticusMB

Verify latest release

  • I verified that the issue exists in the latest pnpm release

pnpm version

10.2.1 and 9.15.5

Which area(s) of pnpm are affected? (leave empty if unsure)

No response

Link to the code that reproduces this issue or a replay of the bug

https://github.com/Divine-Software/WSF/tree/4d68b7c5d60069af68d4523496ea91b8ee7091dc

Reproduction steps

As mentioned in #9059, pnpm link is not working for me. I prepared the Dockerfile below to demonstrate the issue (build with docker build . -t linktest-9 --target v9 or docker build . -t linktest-10 --target v10, depending on what pnpm version to check).

Turns out it all works just fine. So it seems to only affect macOS? See below.

NOTE: WSF has "packageManager": "pnpm@9.15.5", in package.json.

# syntax=docker/dockerfile:1

from node as base
workdir /src
env PNPM_HOME=/usr/local/sbin

run <<EOF
    apt update
    apt install -y openjdk-17-jdk-headless
    apt install -y build-essential libcairo2-dev libpango1.0-dev libjpeg-dev libgif-dev librsvg2-dev
    corepack enable
EOF

run <<EOF
    git clone https://github.com/Divine-Software/WSF.git
    git -C WSF checkout 4d68b7c
    make -C WSF all
    (cd WSF/uri && pnpm link --global)
    (cd WSF/x4e && pnpm link --global)
EOF

workdir /src/test

run <<EOF
    mkdir submodule && printf '{
        "name": "submodule",
        "dependencies": {
            "@divine/headers": "^2",
            "@divine/uri": "~0.6"
        }
    }' > submodule/package.json
    printf '{
        "name": "test",
        "dependencies": {
            "@divine/x4e": "~0.4"
        }
    }' > package.json
    printf 'packages:\n- submodule\n' > pnpm-workspace.yaml
EOF

from base as v9

run <<EOF
    corepack use pnpm@9
    pnpm install

    pnpm link --global @divine/x4e
    (cd submodule && pnpm link --global @divine/uri)
#    pnpm -C submodule link --global @divine/uri

    test $(node -p 'require("@divine/x4e/package.json").version') == '1.0.0'
    cd submodule test $(node -p 'require("@divine/uri/package.json").version') == '1.0.0'
EOF

from base as v10

run <<EOF
    corepack use pnpm@10
    pnpm install

    pnpm link @divine/x4e
    (cd submodule && pnpm link @divine/uri)
#    pnpm -C submodule link @divine/uri

    test $(node -p 'require("@divine/x4e/package.json").version') == '1.0.0'
    cd submodule test $(node -p 'require("@divine/uri/package.json").version') == '1.0.0'
EOF

So, on macOS, after a manual checkout and make all of WSF:

  1. rm -rf $PNPM_HOME/global
  2. (cd uri && pnpm link --global)
  3. (cd x4e && pnpm link --global)

So far so good.

martin@iris:wsf (master)$ find $PNPM_HOME/global -exec ls -ld --color {} +
drwxr-xr-x  3 martin  staff   96  8 Feb 16:42 /Users/martin/Library/pnpm//global
drwxr-xr-x  6 martin  staff  192  8 Feb 16:42 /Users/martin/Library/pnpm//global/5
drwxr-xr-x  3 martin  staff   96  8 Feb 16:42 /Users/martin/Library/pnpm//global/5/.pnpm
-rw-r--r--  1 martin  staff  523  8 Feb 16:42 /Users/martin/Library/pnpm//global/5/.pnpm/lock.yaml
drwxr-xr-x  4 martin  staff  128  8 Feb 16:42 /Users/martin/Library/pnpm//global/5/node_modules
-rw-r--r--  1 martin  staff  615  8 Feb 16:42 /Users/martin/Library/pnpm//global/5/node_modules/.pnpm-workspace-state.json
drwxr-xr-x  4 martin  staff  128  8 Feb 16:42 /Users/martin/Library/pnpm//global/5/node_modules/@divine
lrwxr-xr-x  1 martin  staff   39  8 Feb 16:42 /Users/martin/Library/pnpm//global/5/node_modules/@divine/uri -> ../../../../../../source/divine/wsf/uri
lrwxr-xr-x  1 martin  staff   39  8 Feb 16:42 /Users/martin/Library/pnpm//global/5/node_modules/@divine/x4e -> ../../../../../../source/divine/wsf/x4e
-rw-r--r--  1 martin  staff  298  8 Feb 16:42 /Users/martin/Library/pnpm//global/5/package.json
-rw-r--r--  1 martin  staff  523  8 Feb 16:42 /Users/martin/Library/pnpm//global/5/pnpm-lock.yaml

Then, somewhere else (no packageManager so using pnpm 10 now):

mkdir submodule && printf '{
    "name": "submodule",
    "dependencies": {
        "@divine/headers": "^2",
        "@divine/uri": "~0.6"
    }
}' > submodule/package.json

printf '{
    "name": "test",
    "dependencies": {
        "@divine/x4e": "~0.4"
    }
}' > package.json

printf 'packages:\n- submodule\n' > pnpm-workspace.yaml

pnpm install
pnpm link @divine/x4e
(cd submodule && pnpm link @divine/uri)

Things become even weirder if I instead force pnpm 9 via packageManager. In fresh directory:

mkdir submodule && printf '{
    "name": "submodule",
    "dependencies": {
        "@divine/headers": "^2",
        "@divine/uri": "~0.6"
    }
}' > submodule/package.json

printf '{
    "name": "test",
    "packageManager": "pnpm@9.15.5",
    "dependencies": {
        "@divine/x4e": "~0.4"
    }
}' > package.json

printf 'packages:\n- submodule\n' > pnpm-workspace.yaml

pnpm install
pnpm link --global @divine/x4e
(cd submodule && pnpm link --global @divine/uri)

Describe the Bug

submodule

pnpm -C submodule link ... doesn't work. -C submodule is not respected.

pnpm 10

  • There is a dangling symlink at node_modules/@divine/uri which is unexpected, since only submodule depends on and linked @divine/uri.
  • There is another dangling symlink at submodule/node_modules/@divine/uri. At least the link is expected, but it points to somthing that doesn't exist.

pnpm 9

martin@iris:test$ pnpm link --global @divine/x4e
ERROR  Symlink path is the same as the target path (/Users/martin/Library/pnpm/global/5/node_modules/@divine/x4e)

pnpm: Symlink path is the same as the target path (/Users/martin/Library/pnpm/global/5/node_modules/@divine/x4e)
    at symlinkDir (/opt/homebrew/Cellar/pnpm/10.2.1/libexec/lib/node_modules/pnpm/dist/pnpm.cjs:101356:15)
    at symlinkDirectRootDependency (/opt/homebrew/Cellar/pnpm/10.2.1/libexec/lib/node_modules/pnpm/dist/pnpm.cjs:147476:58)
    at async /opt/homebrew/Cellar/pnpm/10.2.1/libexec/lib/node_modules/pnpm/dist/pnpm.cjs:149107:11
    at async Promise.all (index 1)
    at async linkDirectDepsOfProject (/opt/homebrew/Cellar/pnpm/10.2.1/libexec/lib/node_modules/pnpm/dist/pnpm.cjs:149105:7)
    at async Promise.all (index 0)
    at async linkDirectDeps (/opt/homebrew/Cellar/pnpm/10.2.1/libexec/lib/node_modules/pnpm/dist/pnpm.cjs:149046:34)
    at async linkPackages (/opt/homebrew/Cellar/pnpm/10.2.1/libexec/lib/node_modules/pnpm/dist/pnpm.cjs:187911:24)
    at async _installInContext (/opt/homebrew/Cellar/pnpm/10.2.1/libexec/lib/node_modules/pnpm/dist/pnpm.cjs:188997:25)
    at async installInContext (/opt/homebrew/Cellar/pnpm/10.2.1/libexec/lib/node_modules/pnpm/dist/pnpm.cjs:189341:16)
martin@iris:test$ (cd submodule && pnpm link --global @divine/uri)
 WARN  The package @divine/uri, which you have just pnpm linked, has the following peerDependencies specified in its package.json:

  - @divine/headers@workspace:^2.0.4,   - chokidar@^4.0.3

The linked in dependency will not resolve the peer dependencies from the target node_modules.
This might cause issues in your project. To resolve this, you may use the "file:" protocol to reference the local dependency.
 WARN  Installing a dependency from a non-existent directory: /Users/martin/Library/pnpm/global/5/node_modules/@divine/x4e

martin@iris:test$ (cd submodule && pnpm link --global @divine/uri) 
 ERROR  Symlink path is the same as the target path (/Users/martin/Library/pnpm/global/5/node_modules/@divine/uri)

pnpm: Symlink path is the same as the target path (/Users/martin/Library/pnpm/global/5/node_modules/@divine/uri)
    at symlinkDir (/opt/homebrew/Cellar/pnpm/10.2.1/libexec/lib/node_modules/pnpm/dist/pnpm.cjs:101356:15)
    at symlinkDirectRootDependency (/opt/homebrew/Cellar/pnpm/10.2.1/libexec/lib/node_modules/pnpm/dist/pnpm.cjs:147476:58)
    at async /opt/homebrew/Cellar/pnpm/10.2.1/libexec/lib/node_modules/pnpm/dist/pnpm.cjs:149107:11
    at async Promise.all (index 0)
    at async linkDirectDepsOfProject (/opt/homebrew/Cellar/pnpm/10.2.1/libexec/lib/node_modules/pnpm/dist/pnpm.cjs:149105:7)
    at async Promise.all (index 0)
    at async linkDirectDeps (/opt/homebrew/Cellar/pnpm/10.2.1/libexec/lib/node_modules/pnpm/dist/pnpm.cjs:149046:34)
    at async linkPackages (/opt/homebrew/Cellar/pnpm/10.2.1/libexec/lib/node_modules/pnpm/dist/pnpm.cjs:187911:24)
    at async _installInContext (/opt/homebrew/Cellar/pnpm/10.2.1/libexec/lib/node_modules/pnpm/dist/pnpm.cjs:188997:25)
    at async installInContext (/opt/homebrew/Cellar/pnpm/10.2.1/libexec/lib/node_modules/pnpm/dist/pnpm.cjs:189341:16)
martin@iris:test$ find $PNPM_HOME/global -exec ls -ld --color {} +
drwxr-xr-x  3 martin  staff   96  8 Feb 16:42 /Users/martin/Library/pnpm//global
drwxr-xr-x  6 martin  staff  192  8 Feb 17:01 /Users/martin/Library/pnpm//global/5
drwxr-xr-x  2 martin  staff   64  8 Feb 17:01 /Users/martin/Library/pnpm//global/5/.pnpm
drwxr-xr-x  4 martin  staff  128  8 Feb 16:42 /Users/martin/Library/pnpm//global/5/node_modules
-rw-r--r--  1 martin  staff  615  8 Feb 16:42 /Users/martin/Library/pnpm//global/5/node_modules/.pnpm-workspace-state.json
drwxr-xr-x  3 martin  staff   96  8 Feb 17:01 /Users/martin/Library/pnpm//global/5/node_modules/@divine
lrwxr-xr-x  1 martin  staff   39  8 Feb 16:42 /Users/martin/Library/pnpm//global/5/node_modules/@divine/uri -> ../../../../../../source/divine/wsf/uri
-rw-r--r--  1 martin  staff  280  8 Feb 17:01 /Users/martin/Library/pnpm//global/5/package.json
-rw-r--r--  1 martin  staff  523  8 Feb 16:42 /Users/martin/Library/pnpm//global/5/pnpm-lock.yaml
  1. Note how pnpm 9 even messed up $PNPM_HOME/global!
  2. Note the version numbers in the stack trace. v9 was expected.
  3. Even more fun: Try with and without --global!
martin@iris:test$ pnpm link --global @divine/x4e
 WARN  Installing a dependency from a non-existent directory: /Users/martin/Library/pnpm/global/5/node_modules/@divine/x4e
 WARN  Installing a dependency from a non-existent directory: /Users/martin/Library/pnpm/global/5/node_modules/@divine/x4e
 ERROR  Symlink path is the same as the target path (/Users/martin/Library/pnpm/global/5/node_modules/@divine/uri)

pnpm: Symlink path is the same as the target path (/Users/martin/Library/pnpm/global/5/node_modules/@divine/uri)
    at symlinkDir (/opt/homebrew/Cellar/pnpm/10.2.1/libexec/lib/node_modules/pnpm/dist/pnpm.cjs:101356:15)
    at symlinkDirectRootDependency (/opt/homebrew/Cellar/pnpm/10.2.1/libexec/lib/node_modules/pnpm/dist/pnpm.cjs:147476:58)
    at async /opt/homebrew/Cellar/pnpm/10.2.1/libexec/lib/node_modules/pnpm/dist/pnpm.cjs:149107:11
    at async Promise.all (index 0)
    at async linkDirectDepsOfProject (/opt/homebrew/Cellar/pnpm/10.2.1/libexec/lib/node_modules/pnpm/dist/pnpm.cjs:149105:7)
    at async Promise.all (index 0)
    at async linkDirectDeps (/opt/homebrew/Cellar/pnpm/10.2.1/libexec/lib/node_modules/pnpm/dist/pnpm.cjs:149046:34)
    at async linkPackages (/opt/homebrew/Cellar/pnpm/10.2.1/libexec/lib/node_modules/pnpm/dist/pnpm.cjs:187911:24)
    at async _installInContext (/opt/homebrew/Cellar/pnpm/10.2.1/libexec/lib/node_modules/pnpm/dist/pnpm.cjs:188997:25)
    at async installInContext (/opt/homebrew/Cellar/pnpm/10.2.1/libexec/lib/node_modules/pnpm/dist/pnpm.cjs:189341:16)


martin@iris:test$ pnpm link @divine/x4e
 ERROR  Symlink path is the same as the target path (/Users/martin/source/divine/test/node_modules/@divine/x4e)

pnpm: Symlink path is the same as the target path (/Users/martin/source/divine/test/node_modules/@divine/x4e)
    at symlinkDir (/Users/martin/Library/pnpm/.tools/pnpm/9.15.5/node_modules/.pnpm/pnpm@9.15.5/node_modules/pnpm/dist/pnpm.cjs:103697:15)
    at symlinkDirectRootDependency (/Users/martin/Library/pnpm/.tools/pnpm/9.15.5/node_modules/.pnpm/pnpm@9.15.5/node_modules/pnpm/dist/pnpm.cjs:143529:58)
    at async /Users/martin/Library/pnpm/.tools/pnpm/9.15.5/node_modules/.pnpm/pnpm@9.15.5/node_modules/pnpm/dist/pnpm.cjs:185947:9
    at async Promise.all (index 0)
    at async link (/Users/martin/Library/pnpm/.tools/pnpm/9.15.5/node_modules/.pnpm/pnpm@9.15.5/node_modules/pnpm/dist/pnpm.cjs:185944:7)
    at async Object.handler (/Users/martin/Library/pnpm/.tools/pnpm/9.15.5/node_modules/.pnpm/pnpm@9.15.5/node_modules/pnpm/dist/pnpm.cjs:187843:27)
    at async /Users/martin/Library/pnpm/.tools/pnpm/9.15.5/node_modules/.pnpm/pnpm@9.15.5/node_modules/pnpm/dist/pnpm.cjs:223175:21
    at async main (/Users/martin/Library/pnpm/.tools/pnpm/9.15.5/node_modules/.pnpm/pnpm@9.15.5/node_modules/pnpm/dist/pnpm.cjs:223134:34)
    at async runPnpm (/Users/martin/Library/pnpm/.tools/pnpm/9.15.5/node_modules/.pnpm/pnpm@9.15.5/node_modules/pnpm/dist/pnpm.cjs:223406:5)
    at async /Users/martin/Library/pnpm/.tools/pnpm/9.15.5/node_modules/.pnpm/pnpm@9.15.5/node_modules/pnpm/dist/pnpm.cjs:223398:7

Expected Behavior

Basically, I just want pnpm link to work again. 😢

Which Node.js version are you using?

v23.7.0

Which operating systems have you used?

  • macOS
  • Windows
  • Linux

If your OS is a Linux based, which one it is? (Include the version if relevant)

No response

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions