@salesforce/plugin-trust bin points to unpublished bin/dev, breaking npm install

Open Beginner friendly
#3,644 6 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
76/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Active
Tech stack
javascript, node.js
Domain
cli, release

Research direction

Inspect the @salesforce/plugin-trust package manifest and its published bin files, especially bin/run.js and bin/dev.js. Reproduce the package contents with npm pack and verify installation with the provided npm commands; done means the declared sf-trust executable targets a published file, the bin link is created, and subsequent npm install completes.

Written by the indexing model from the issue text.

Description

bug investigating validated
Summary

@salesforce/plugin-trust declares a bin entry that points at a file it does not publish:

"bin": { "sf-trust": "bin/dev" }

The published tarball contains bin/dev.js, bin/dev.cmd, bin/run.js and bin/run.cmd — there is no extensionless bin/dev. Confirmed in @salesforce/plugin-trust@4.0.9 (bundled with @salesforce/cli@2.149.9) and @salesforce/plugin-trust@4.0.11 (bundled with the current latest @salesforce/cli@2.150.6).

Because the bin target doesn't resolve, npm's bin-links silently skips it (link-gently.js, "if the script or manpage isn't there, just ignore it"), so node_modules/@salesforce/cli/node_modules/.bin/sf-trust is never created — not even by a clean install.

On its own that would be a harmless cosmetic bug. In practice it permanently breaks npm install for every project that depends on @salesforce/cli, because it trips a latent npm/arborist bug:

  • arborist's getAction classifies a node as CHANGE when any of its declared bins is missing from disk, so plugin-trust is CHANGE on every install forever, despite matching version and integrity.
  • That CHANGE node lives inside @salesforce/cli's npm-shrinkwrap.json subtree, which arborist only diffs after it has already decided which directories to move aside for rollback. The node therefore has no rollback entry, and npm install crashes with ERR_INVALID_ARG_TYPE: The "from" argument must be of type string. Received undefined.
  • The crash happens before the step that creates bin links, so the missing link can never get created and every subsequent install fails identically.

I've filed the npm-side analysis at https://github.com/npm/cli/issues/4907 (an open issue since 2022 that nobody had root-caused). npm should certainly fix its end — but @salesforce/cli is currently the trigger that makes it fire for everyone, and the fix on this side is a one-line change.

Suggested fix: point the bin at the published production entry point rather than the ts-node development one:

"bin": { "sf-trust": "bin/run.js" }

bin/dev.js has the shebang #!/usr/bin/env -S node --loader ts-node/esm and is not usable from a published package anyway (ts-node isn't a runtime dependency). bin/run.js is the correct entry. Alternatively, if sf-trust isn't meant to be a user-facing executable at all, drop the bin field.

Steps To Reproduce

A dedicated repo isn't needed — this reproduces from a two-line package.json with no Salesforce project or org involved, since the failure happens at npm install time. Verified on the latest @salesforce/cli@2.150.6 against the public npm registry.

mkdir sf-bin-repro && cd sf-bin-repro
cat > package.json <<'EOF'
{ "name": "sf-bin-repro", "version": "1.0.0", "private": true,
  "devDependencies": { "@salesforce/cli": "2.150.6", "lint-staged": "17.4.1" } }
EOF

# 1. clean install — succeeds
npm install

# 2. the declared bin was never linked
ls -la node_modules/@salesforce/cli/node_modules/.bin/sf-trust

# 3. now update any unrelated dependency, with node_modules still in place
npm i -D lint-staged@17.5.0

To see the packaging bug in isolation, without any npm interaction:

npm pack @salesforce/plugin-trust@4.0.11
tar tzf salesforce-plugin-trust-4.0.11.tgz | grep '^package/bin/'
# package/bin/dev.cmd
# package/bin/dev.js
# package/bin/run.cmd
# package/bin/run.js          <-- no extensionless "bin/dev"

npm view @salesforce/plugin-trust@4.0.11 bin
# { 'sf-trust': 'bin/dev' }
Expected result
  • node_modules/@salesforce/cli/node_modules/.bin/sf-trust exists after installation, pointing at a file that is actually published.
  • Step 3 completes normally.
Actual result

Step 2:

ls: node_modules/@salesforce/cli/node_modules/.bin/sf-trust: No such file or directory

Step 3:

npm error code ERR_INVALID_ARG_TYPE
npm error The "from" argument must be of type string. Received undefined

Every subsequent npm install in that project fails the same way until node_modules is deleted entirely — and it starts failing again as soon as the tree is reinstalled, because the bin link is still never created.

A retry after the first crash produces a second, different failure, because npm's failed rollback leaves its staging directories behind:

npm error code ENOTEMPTY
npm error syscall rename
npm error path .../node_modules/lint-staged
npm error dest .../node_modules/.lint-staged-gfX1MQHW
Additional information

Verified that this is the sole cause of the install failure: creating the missing link by hand makes the node compare equal and the install succeed immediately, with no other change.

P=node_modules/@salesforce/cli/node_modules/@salesforce/plugin-trust
printf '#!/usr/bin/env node\n' > "$P/bin/dev" && chmod +x "$P/bin/dev"
ln -sfn ../@salesforce/plugin-trust/bin/dev \
        node_modules/@salesforce/cli/node_modules/.bin/sf-trust

npm i -D lint-staged
# added 1 package, changed 163 packages, and audited 2563 packages in 10s

Measured with arborist's own diffing API before and after that change:

before: never-retired orphan nodes: 91,  orphans that trigger the crash: 1  (@salesforce/plugin-trust)
after : never-retired orphan nodes: 90,  orphans that trigger the crash: 0

Note on the issue template: sf doctor isn't applicable here — the CLI itself runs fine, and the failure is in npm install of a project that depends on @salesforce/cli, before any sf command is involved.

System Information

Shell: zsh on macOS (Darwin 25.6.0, arm64), Node v22.22.3, npm 10.9.8.

The project below pins @salesforce/cli@2.149.9, but as noted above the packaging bug and the resulting install failure are both confirmed on the current latest, 2.150.6.

{
  "architecture": "darwin-arm64",
  "cliVersion": "@salesforce/cli/2.149.9",
  "nodeVersion": "node-v22.22.3",
  "osVersion": "Darwin 25.6.0",
  "rootPath": "/Users/…/node_modules/@salesforce/cli",
  "shell": "zsh",
  "pluginVersions": [
    "@oclif/plugin-autocomplete 3.2.56 (core)",
    "@oclif/plugin-commands 4.1.63 (core)",
    "@oclif/plugin-help 6.2.58 (core)",
    "@oclif/plugin-not-found 3.2.93 (core)",
    "@oclif/plugin-plugins 5.4.87 (core)",
    "@oclif/plugin-search 1.2.54 (core)",
    "@oclif/plugin-update 4.7.59 (core)",
    "@oclif/plugin-version 2.2.57 (core)",
    "@oclif/plugin-warn-if-update-available 3.1.73 (core)",
    "@oclif/plugin-which 3.2.61 (core)",
    "@salesforce/cli 2.149.9 (core)",
    "agent 2.0.3 (core)",
    "apex 4.1.0 (core)",
    "api 2.0.9 (core)",
    "auth 5.0.6 (core)",
    "code-analyzer 5.0.0 (user) published 495 days ago (Tue Apr 29 2025) (latest is 5.16.0)",
    "data 5.1.5 (core)",
    "deploy-retrieve 4.1.2 (core)",
    "info 4.0.9 (core)",
    "lightning-dev 3.5.1 (user) published 375 days ago (Wed Aug 27 2025) (latest is 6.2.18)",
    "limits 4.0.3 (core)",
    "marketplace 2.0.5 (core)",
    "org 6.0.9 (core)",
    "packaging 3.0.5 (core)",
    "schema 4.0.5 (core)",
    "settings 3.0.5 (core)",
    "sobject 2.0.5 (core)",
    "telemetry 4.0.5 (core)",
    "templates 57.0.9 (core)",
    "trust 4.0.9 (core)",
    "ui-bundle-dev 1.2.2 (user) published 159 days ago (Tue Mar 31 2026) (latest is 1.2.4)",
    "user 5.0.1 (core)"
  ]
}
Dominant language
No language data
Stars
571
Forks
80
Avg merge
7d 7h
Merged PRs (30d)
3

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from forcedotcom/cli

All issues in forcedotcom/cli

Similar issues

More CLI issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.