Skip to content

vp cannot resolve node through a relative PATH entry — breaks Vite+'s own git hooks #2326

Description

@andrefelipe

Summary

vp fails to resolve node when the PATH entry containing it is relative (e.g. ./node_modules/.bin), erroring with:

error: Cannot find binary path for command 'node'

The same directory spelled as an absolute path works fine.

This isn't hypothetical: Vite+'s own git-hook runner constructs exactly such a relative entry, so vp inside a pre-commit hook fails whenever the ambient environment doesn't already provide a node of its own — which is the normal case for GUI git clients (VS Code, Tower, Fork).

Reproduction

Standalone, no hooks involved:

mkdir vp-relative-path-repro && cd vp-relative-path-repro
echo '{"name":"repro","private":true,"type":"module"}' > package.json
npm install vite-plus@0.2.7 node@24

# absolute PATH entry — works
PATH="$PWD/node_modules/.bin:/usr/bin:/bin" ./node_modules/.bin/vp check
#   Found formatting issues in 1 file …

# relative PATH entry — fails
PATH="./node_modules/.bin:/usr/bin:/bin" ./node_modules/.bin/vp check
#   error: Cannot find binary path for command 'node'

The only difference between the two runs is $PWD/node_modules/.bin vs ./node_modules/.bin. ./node_modules/.bin/node exists and is executable in both, and the working directory is the project root in both.

A relative entry appears to abort the search, not just be skipped

An absolute node later on PATH does not rescue it:

PATH="./node_modules/.bin:/usr/bin:/bin:/opt/homebrew/bin" ./node_modules/.bin/vp check
#   error: Cannot find binary path for command 'node'

/opt/homebrew/bin/node exists (v26.5.0) and is absolute, yet lookup still fails. So the relative entry seems to abort the scan rather than be ignored or resolved against the cwd.

Why the git hooks hit this

.vite-hooks/_/h, generated by Vite+, builds its PATH from $0:

d="$(dirname "$(dirname "$(dirname "$0")")")"
export PATH="$d/node_modules/.bin:$PATH"

Git invokes hooks by a relative path (.vite-hooks/_/pre-commit), so d collapses to . and the exported entry is ./node_modules/.bin — precisely the failing shape.

Committing from a terminal usually survives, because the login shell already exports an absolute node that wins the lookup. Committing from a GUI client, whose environment carries no node, dies before the hook body runs:

[STARTED] Cleaning up temporary files...
[COMPLETED] Cleaning up temporary files...
error: Cannot find binary path for command 'node'
VITE+ - pre-commit script failed (code 1)

Expected

vp resolves node through a relative PATH entry (resolved against the current working directory, as the shell does), or at minimum skips the entry and continues scanning the rest of PATH.

Actual

Lookup fails with Cannot find binary path for command 'node', even when a valid absolute node appears later on PATH.

Environment

  • vite-plus 0.2.7 (npm) — also reproduces on 0.2.5
  • macOS 26.5.2, arm64
  • node 24.18.0

Note: the standalone vp binary (~/.vite-plus/bin/vp) is not affected — it bundles its own node and never resolves one from PATH. Only the npm-distributed #!/usr/bin/env node build hits this, which is what a project's hooks actually run.

Workaround

Prepend an absolute entry in the hook body, ahead of the runner's relative one:

PATH="$(pwd)/node_modules/.bin:$PATH"

Suggested fix

Either or both:

  1. In the binary lookup, resolve relative PATH entries against the cwd, and don't let one abort the remaining scan.
  2. In h, absolutize d before exporting it.

Metadata

Metadata

Assignees

Type

No type

Fields

Priority

None yet

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions