[Bug?]: pnpm linker — cross-device link not permitted
Self-service
- [ ] I'd be willing to implement a fix
Describe the bug
Sometimes (especially in docker environments like CI for example) cacheFolder and the project could be located on different volumes. Normally it's okay because we just copy packages from cache to project, but it's could be a problem when people use nodeLinker: "pnpm". Because we have content addressing index there and it's not possible to create cross-device links.
[Error: EXDEV: cross-device link not permitted, link '/root/.yarn/berry/index/a6/a69a7f3d4a4636bf9035bc53c05b2d99a7b8af7f.dat' -> '/workspace/node_modules/.store/react-npm-18.2.0-1eae08fee2/package/index.js'] {
errno: -18,
code: 'EXDEV',
syscall: 'link',
path: '/root/.yarn/berry/index/a6/a69a7f3d4a4636bf9035bc53c05b2d99a7b8af7f.dat',
dest: '/workspace/node_modules/.store/react-npm-18.2.0-1eae08fee2/package/index.js'
}
To reproduce
I tried to make it with sherlock but looks like it works a bit differently now with volumes. So I created repro in codesandbox itself https://codesandbox.io/p/sandbox/yarn-cross-device-link-not-permitted-ik1voj
Environment
System:
OS: Linux 5.15 Debian GNU/Linux 11 (bullseye) 11 (bullseye)
CPU: (2) x64 AMD EPYC
Binaries:
Node: 18.15.0 - /tmp/xfs-1c7a3680/node
Yarn: 4.0.0-rc.40.git.20230316.hash-f81af69 - /tmp/xfs-1c7a3680/yarn
npm: 9.5.0 - /usr/local/bin/npm
Additional context
I guess it makes sense to catch errors like this and fallback to copy. What do you think?
Just chiming in here to say that with the release of Yarn 4, I decided that I would try out the pnpm linker, but I was blocked by this error (e.g. "cross-device link not permitted") and had to switch back to node_modules.
My story is that I installed Windows on my C drive, and then I store my repositories (and other data) on a D drive, which AFAIK is a common pattern for desktop computers. Subsequently, when installing any repo/project with the pnpm linker, I get this error, because the cache is by default located in my user directory, e.g. "C:\Users\james\AppData\Local\Yarn\Berry\index\1a\1a4e1d54482ab3f7d2f02b0421d0127795cbc10c.dat".
I guess it makes sense to catch errors like this and fallback to copy. What do you think?
If this is indeed a technical limitation where hard links must remain on the same volume, then in my case I would prefer that Yarn simply set up a cache on my D drive instead of my C drive automatically without me having to do anything else, as that would be vastly better UX/DX.
(This is exactly what pnpm does by default AFAIK.)
For whatever reason, I ran into issue on github actions. Didn't know it will migrate cache from another drive: https://github.com/psychobolt/vite-storybook-boilerplate/actions/runs/8088993299/job/22104165674#step:4:104
I had this issue with GitHub Actions Windows runners and used these settings to prevent Yarn from linking across drives. Based on the docs it sounded like setting enableGlobalCache and enableMirror to false should be good enough, but I kept getting errors until I also set the globalFolder to be a location on the same drive (and within the repo in this case).
enableGlobalCache: false
enableMirror: false
globalFolder: .yarn/berry
I think in either cases for github Windows runner, LOCALAPPDATA and homedir will refer to the OS home drive. One way is to configure globalFolder as suggested by @ecraig12345 , but I'd like to avoid sharing this system-wide setting. We want to avoid overriding LOCALAPPDATA for package builds as well. For my github workflow, using a Windows runner e.g.
- name: Set Yarn global folder
if: runner.os == 'Windows'
run: yarn config set globalFolder "${{ runner.temp }}\Yarn\Berry"
is tricky, as I need to ensure yarn config set is following my prettier standards or my CI will error during linting. I could do a simple git stash to avoid all that or ignore standard formatting on the config, but using a override variable like YARN_GLOBAL_FOLDER be would ideal in opt-in scenarios like these.
Here is a similiar case, but happening in bitbucket pipelines:
➤ YN0000: ┌ Link step
➤ YN0001: │ Error: EXDEV: cross-device link not permitted, link '/root/.yarn/berry/index/2c/2cc5fdd737af90eb3846d7c4342e45160f7207d4.dat' -> '/opt/atlassian/pipelines/agent/build/apps/svelte-app/node_modules/.store/@dotenvx-dotenvx-npm-0.31.1-5f7bc83e8d/package/LICENSE'
My CI is configured to run on image: atlassian/default-image:4
Update: I guess since my main project is using Yarn's default Plug N' Play, in my case, I would only need to check the hybrid workspace and change global folder into a fallback local copy. Simple enough to wrap a CLI script around this, maybe not the best, but I'll leave it here in case anyone wants a reference...
Got the same thing with me, it was working fine in Linux, but got problem in Windows. Any idea how to workaround this? Tried everything, still didn't work.
I left a related comment in https://github.com/yarnpkg/berry/issues/2701#issuecomment-2081257504. I don't think copying cache files is optimal in the case if there were files to be fetched before the linking stage. It may be just better to handle it gracefully with a preinstall or bootstrap step. e.g. check if there exist a pnpm workspace and if so set globalFolder to same drive, copy should be before fetch imo...
how to fix (workaround) this for windows:
enableGlobalCache: truein the config.- remove all from the
%LocalAppData%/yarn(optionally, to free some space) - open local copy of the
yarn.cjs(if not yet stored it locally - do it, change the config) - find in the yarn.cjs the next string
process.env.LOCALAPPDATAand insert beforeprocess.env.YRN_CACHE_GLOBAL_FOLDER - ensure that you added the right path to the
YRN_CACHE_GLOBAL_FOLDERenv variable (do not useYARNprefix as it's being scanned by the yarn) - logoff if needed.
- run yarn install.
- PS if you use/needed the
cacheFolderconfiguration parameter, there is another default env variableYARN_CACHE_FOLDERand you may need tweak more this workaround.
I'm trying to start using pnpm for the react native project which is based on the yarn ws and contains ~20 packages including the service ones. As it is for now, I'm having different issues but not the "EXDEV: cross-device link not permitted" anymore. There is a chance that I will post some updates later.
please, confirm if my workaround helped, I would consider creating a pr.
This is not only an issue for nodeLinker: "pnpm", but also for nodeLinker: "pnp" when using esbuild (which is also used by vite, it seems): evanw/esbuild#3131
The generated .pnp.data.json always contains relative paths, and Windows does not support relative paths between different drive letters. According to this comment by esbuild author evanw, yarn contains some hack (?) to make such relative links work, but esbuild does not and fails.
- do links in
.pnp.data.jsonbetween different drive letters have to be relative? - would it already help if yarn's default for the global cache folder made sure that it's on the same Windows drive?
- pnpm seems to have done it this way (commit)