GeezerVison is showing github.com — Vendored npm refusal for a symlinked package-lock.json says "nothing was written" but leaves the vendored tarball behind, then prints "Vendored 1 package" and tells you to commit .socket/vendor/ · Issue #898 · SocketDev/socket-patch
Vendored npm refusal for a symlinked package-lock.json says "nothing was written" but leaves the vendored tarball behind, then prints "Vendored 1 package" and tells you to commit .socket/vendor/ #898Description[agent] Found by the scheduled npm bug-hunt routine (ledger #302).
Summary
#802 (fix for #627) made vendored mode refuse a symlinked lockfile with redirect_symlinked_file_unsupported ("…; nothing was written"). That refusal fires in the run's final group commit, after the per-package loop has already downloaded and written the vendored artifact. Nothing cleans that artifact up. So after the refusal:
.socket/vendor/npm/<uuid>/left-pad-1.3.0.tgz and socket-patch.vendor.json are left in the tree, with no state.json entry and no lock wiring.
- The human output prints the error, then
Vendored 1 package. and the next step "Commit .socket/vendor/ and the updated lockfiles to make the patches portable."
--json reports vendor.summary.applied: 1 and an applied event next to vendor.error.code: redirect_symlinked_file_unsupported.
vendor --check then exits 0 with zero events, and rollback / remove say "Manifest not found". Only vendor --revert (which the message doesn't mention) deletes the orphan files.
The Bun routine saw this first on Bun and on npm 10 (handover on ledger #302). I've confirmed it on npm 8, 10 and 12.
Impact
- The refusal message says "nothing was written", which is false.
- The success-style summary and "commit .socket/vendor/" advice contradict the exit-1 error. A user who follows the advice commits an unwired tarball and ledger marker while the lock still resolves the registry copy.
- Fails safe: the lock is untouched, the install stays unpatched, and
vex finds nothing to attest (exit 2). So no false VEX claim, just a misleading run and orphan files.
Repro (Linux, main 9c43dfc)
A local mock patch API serves a free patch for pkg:npm/[email protected] (granted tarball from patches/package).
mkdir app && cd app
echo '{"name":"app","version":"1.0.0","dependencies":{"left-pad":"1.3.0"}}' > package.json
npm install
mkdir locks && mv package-lock.json locks/ && ln -s locks/package-lock.json package-lock.json
git init -q && echo node_modules > .gitignore && git add -A && git commit -qm init
socket-patch scan --mode vendored --yes --api-url $MOCK --org o --api-token x
# Error: package-lock.json is a symbolic link; … and re-run; nothing was written
# Vendored 1 package.
# Next steps:
# 1. Commit .socket/vendor/ and the updated lockfiles to make the patches portable.
# exit 1
git status --short --untracked-files=all
# ?? .socket/vendor/npm/5a6b7c8d-…/left-pad-1.3.0.tgz
# ?? .socket/vendor/npm/5a6b7c8d-…/socket-patch.vendor.json
socket-patch vendor --check --json # exit 0, status success, events []
socket-patch rollback --yes # Error: Manifest not found
socket-patch vendor --revert --yes # exit 0; the orphan files are removed
--json excerpt:
"vendor": {"status": "error",
"events": [{"action": "applied", "purl": "pkg:npm/[email protected]", …},
{"action": "skipped", "errorCode": "vendor_prebuilt_downloaded", …}],
"summary": {"applied": 1, "failed": 0, …},
"error": {"code": "redirect_symlinked_file_unsupported", "message": "… nothing was written"}}
Replacing the link with a regular file and re-running works (it reuses the orphan, wires the lock, and a fresh npm ci installs the patched bytes). The --dry-run warning vendor_would_refuse_symlinked_file is correct.
Expected vs actual
- Expected: what Fix vendored mode replacing symlinked lockfiles (#627) #802's commit message and the hosted refusal promise: a refusal "before writing anything", leaving "the link, its target and the vendor ledger untouched". A whole-project refusal (
hosted::engine::Refusal, "nothing is written") should leave no new files, or at least not claim "nothing was written". The summary shouldn't count a package as vendored, or print commit advice, when the commit was refused.
- Actual: two new files under
.socket/vendor/npm/<uuid>/, Vendored 1 package., applied: 1, and advice to commit them.
OS × version
| OS |
npm (lockfileVersion) |
orphan artifact + "Vendored 1 package" |
runs |
| Linux |
8.19.4 (v2) |
yes |
1 |
| Linux |
10.9.4 (v3) |
yes |
2 |
| Linux |
12.2.0 / Node 24 (v3) |
yes |
1 |
| Linux |
Bun 1.4.2 text bun.lock (from the Bun routine) |
yes |
— |
| macOS / Windows |
not probed; the code path has no OS-specific branch |
|
|
Not a regression: before #802 (6b8c076), vendored mode replaced the link (#627).
Suspect code
crates/socket-patch-cli/src/commands/vendor.rs:3032-3043: the symlinked_target arm of group.commit_changes() marks the error but doesn't remove the artifacts the loop wrote (the dirs the stale_artifacts sweep would otherwise handle), and it leaves the applied events and counts in place.
crates/socket-patch-core/src/hosted/engine.rs:124 (symlink_refusal): the "nothing was written" wording is reused for a refusal that fires after the artifacts are written.
- The summary and next steps (
format_vendor_summary, vendor.rs:572, and the next-steps block around vendor.rs:3180) are printed even though the commit failed.
Related: #627 / #802 (the refusal this completes), #887 (symlinked .socket dir).
Backlog review — 2026-10-08
Priority: P1 → P3. The lockfile remains protected. A leftover staged artifact and misleading success/commit text need cleanup, not P1 incident handling. Activitymikolalysenko commented on Oct 6, 2026 CollaboratorAuthor More actions [agent] Triaged as priority:p1 (npm-family, also seen on Bun). Not a duplicate: #887 is about writes through a symlinked .socket dir. This issue is the group-commit symlink refusal (#802), which fires after the per-package loop has already written the artifacts and leaves the success summary in place. I found no open or merged PR that fixes it.
Generated by Claude Code mikolalysenko commented on Oct 7, 2026 CollaboratorAuthor More actions Being fixed in draft PR #1008 (batch fix for open pm:npm issues).
MetadataMetadataDevelopmentNo branches or pull requestsIssue actions
|