Repository navigation
Description
What version of Bun is running?
1.4.0+34cbb9a40
What platform is your computer?
Confirmed on two platforms:
- Linux 6.18.33.2-microsoft-standard-WSL2 x86_64 x86_64
- Darwin 25.6.0 arm64 arm
What steps can reproduce the bug?
bun prune and bun dedupe both reject a lockfile that bun install considers current, whenever a workspace package lists another workspace package in both a normal dependency field and peerDependencies.
Three files:
// package.json
{ "name": "root", "private": true, "workspaces": ["a", "b"] }// a/package.json
{ "name": "wa", "version": "1.0.0" }// b/package.json
{
"name": "wb",
"version": "1.0.0",
"devDependencies": { "wa": "workspace:*" },
"peerDependencies": { "wa": "workspace:*" },
}bun install
bun prune
bun dedupeWhat is the expected behavior?
bun prune and bun dedupe should agree with bun install that the lockfile is up to date, and proceed.
What do you see instead?
bun install writes the lockfile and reports no changes:
Saved lockfile
Checked 4 installs across 3 packages (no changes) [4.00ms]
Immediately afterwards, both new 1.4 commands claim the lockfile is stale:
$ bun prune
bun prune v1.4.0 (34cbb9a40)
error: bun.lock does not match package.json, nothing to prune
note: run 'bun install' first
exit=1
$ bun dedupe
bun dedupe v1.4.0 (34cbb9a40)
error: bun.lock does not match package.json, nothing to dedupe
note: run 'bun install' first
exit=1
Following the note (bun install) does not help — the state is already converged. bun install --frozen-lockfile exits 0 on the same tree, so install and prune/dedupe disagree about whether the lockfile matches:
$ bun install --frozen-lockfile
Checked 4 installs across 3 packages (no changes) [6.00ms]
exit=0
The generated lockfile records the dependency once in each field, which looks correct:
"b": {
"name": "wb",
"version": "1.0.0",
"devDependencies": { "wa": "workspace:*" },
"peerDependencies": { "wa": "workspace:*" },
},Additional information
Isolated by bisection. The trigger is specifically a workspace-resolved dependency that is also declared as a peer:
b's declaration of the dependency |
bun prune |
|---|---|
peerDependencies only (workspace pkg) |
OK |
dependencies + peerDependencies (workspace pkg, exact version 1.0.0) |
fails |
devDependencies + peerDependencies (workspace pkg, exact version 1.0.0) |
fails |
devDependencies + peerDependencies (workspace pkg, workspace:*) |
fails |
devDependencies + peerDependencies (registry pkg, is-odd@3.0.1) |
OK |
So it is not peer deps in general and not workspace deps in general — only their combination. Both the workspace:* protocol and a plain exact version that happens to resolve to a workspace trigger it. My guess is that the manifest-vs-lockfile comparison in prune/dedupe counts the dependency twice on the manifest side while the lockfile deduplicates it into one resolution, so the counts never line up.
This is worth flagging because the pattern is the normal way to publish a plugin/adapter package: the adapter peer-depends on the core package for consumers, and dev-depends on the same workspace copy to build and test against. I hit it in a monorepo where every UI-integration package does exactly this, which makes bun prune and bun dedupe unusable there. Other lockfile consumers in the same tree (bun install, bun install --frozen-lockfile, bun outdated, bun pm ls) are all fine.
Also confirmed against a lockfile deleted and regenerated from scratch, so it is not a stale-lockfile artifact — the freshly written bun.lock is rejected by the command that would have to read it next.
(This is not a duplicate of 38912 — that one is bun prune declining to remove a leftover isolated store after a linker switch (error: node_modules was installed with the isolated linker). This is a different check with a different message, and reproduces on a fresh hoisted-only install with no linker change.)
Activity
robobun commentedon Aug 24, 2026
Reproduced: with a workspace package listed in both a dependency group and peerDependencies,
bun pruneandbun dedupereject the lockfilebun installjust wrote. The bun.lock loader skips resolving the duplicate peer entry to the workspace path, so the diff against package.json never matches. The open PR #38869 fixes this exact loader bug (it surfaced there asbun installre-resolving a workspace on every run). A regression test for the prune/dedupe symptom is on the branchfarm/a9e82d7a/prune-dedupe-workspace-peer-dup.install: one workspace-link rule so bun.lock reloads match package.js…