Skip to content
Latchkey

husky ".husky/pre-commit: command not found" - Fix Hook Script in CI

This is the runtime side of husky: a Git hook (e.g. .husky/pre-commit) runs but a command inside it - lint-staged, a linter, a formatter - is not found because it was not installed or is not on PATH in that context.

What this error means

A commit or a hook-triggering step fails with .husky/pre-commit: line N: <tool>: command not found. The hook itself runs, but the tool it calls is missing - often in CI commits or environments without devDependencies.

husky output
.husky/pre-commit: line 4: lint-staged: command not found
husky - pre-commit script failed (code 127)

Diagnose it: the shell in CI is not your shell

Package scripts run under a different shell, a different PATH, and a non-interactive environment on a runner. Most scripts that fail only in CI are relying on something the login shell gave them locally: a tool on PATH, an environment variable from a dotfile, or a TTY.

Terminal
# what the script can actually see
npm run env | grep -E "^(PATH|NODE_ENV|CI)=" 

# is the binary on PATH for the script, not just for you?
npm exec -- which <tool> || echo "not resolvable from npm scripts"

# run the exact script with tracing
sh -x -c "$(node -p "require('./package.json').scripts.build")"

Common causes

The hook’s tool is not installed in this context

A hook invoking lint-staged/eslint/prettier fails when those devDependencies are absent (e.g. a production install) or the bare binary is expected on PATH.

PATH does not include node_modules/.bin

Hooks run in a minimal shell. Calling a bare tool name relies on it being on PATH; without npx/node_modules/.bin, it is not found.

How to fix it

Invoke hook tools via the local binary

Call the tool through npm/npx so it resolves from node_modules.

.husky/pre-commit
# .husky/pre-commit
npx --no-install lint-staged
# ensure the tool is a devDependency:
npm install -D lint-staged

Skip hooks where they do not belong

  1. Do not rely on devDependency hook tools in production installs.
  2. In CI that does not need hooks, set HUSKY=0 to disable them.
  3. Ensure any committing CI job installs the hook tools first.

Make failures fail the job

A multi-command script can report success while a middle command failed, which produces the worst kind of CI result: a green build that shipped something broken.

.github/workflows/ci.yml
# pipefail is NOT set by default in every runner shell
- name: Build
  shell: bash
  run: |
    set -euo pipefail
    npm run build | tee build.log

How to prevent it

  • Call hook tools via npx --no-install or node_modules/.bin.
  • Keep hook tools as installed devDependencies.
  • Disable husky (HUSKY=0) in contexts without dev deps.

Frequently asked questions

What causes husky ".husky/pre-commit: command not found"?
There are 2 common causes: the hook’s tool is not installed in this context and path does not include node_modules/.bin. A hook invoking lint-staged/eslint/prettier fails when those devDependencies are absent (e.g.
How do I fix husky ".husky/pre-commit: command not found"?
There are 2 fixes depending on which cause you have: invoke hook tools via the local binary and skip hooks where they do not belong. Work through them in order, since the first is the most common.
What does husky ".husky/pre-commit: command not found" actually mean?
A commit or a hook-triggering step fails with .husky/pre-commit: line N: <tool>: command not found.
How do I stop husky ".husky/pre-commit: command not found" happening again?
Call hook tools via npx --no-install or node_modules/.bin. The prevention section lists 3 changes that keep it from recurring.

Related guides

References

Not every red build is your code. Latchkey repairs the ones that are not, on the runner. Start free → 30-day trial · No credit card