charmbracelet/crush · error
interpreter %q not found and %q not in PATH
Error message
interpreter %q not found and %q not in PATH
What it means
resolveInterpreter reports that the shebang's literal interpreter path does not exist AND its basename cannot be found on PATH. This is the two-part variant of the bare-name lookup failure: the resolver tried os.Stat on the literal path (got fs.ErrNotExist), then exec.LookPath on the basename, and both failed.
Source
Thrown at internal/shell/dispatch.go:246
if statErr == nil {
return path, nil
}
if !errors.Is(statErr, fs.ErrNotExist) {
return "", statErr
}
base := filepath.Base(path)
if base == "" || base == path && !strings.ContainsAny(path, `/\`) {
// Already a bare name — just do a PATH lookup.
resolved, err := exec.LookPath(path)
if err != nil {
return "", fmt.Errorf("interpreter %q not found in PATH", path)
}
return resolved, nil
}
resolved, err := exec.LookPath(base)
if err != nil {
return "", fmt.Errorf("interpreter %q not found and %q not in PATH", path, base)
}
slog.Debug("Shebang interpreter not found; falling back to PATH",
"requested", path, "resolved", resolved)
return resolved, nil
}
// shebang captures the parsed `#!` line. interpreter is the program to
// invoke; args is the list of extra arguments to pass before the script
// path. The kernel's single-arg semantics (for literal paths and for env
// without `-S`) is encoded by returning a single-element args slice
// containing the un-tokenized remainder.
type shebang struct {
interpreter string
args []string
}
// parseShebang extracts the interpreter invocation from probe. It tolerates
// CRLF line endings and a single leading space between `#!` and the path.View on GitHub (pinned to 7944b8e522)
Solutions
- Install the interpreter so the shebang path exists, or place its basename on PATH.
- Edit the shebang to reference an interpreter that exists on the current machine.
- For portability, use `#!/usr/bin/env <name>` form so the resolver can PATH-lookup the name directly.
- On Windows, install Git for Windows and add its usr/bin (bash.exe) to PATH.
Example fix
// before
#!/usr/local/bin/python3
print('hi')
// after
#!/usr/bin/env python3
print('hi') Defensive patterns
Strategy: validation
Validate before calling
interp := "/usr/local/bin/python3"
if _, err := os.Stat(interp); errors.Is(err, fs.ErrNotExist) {
if _, err := exec.LookPath(filepath.Base(interp)); err != nil {
// neither path nor PATH has it — fix environment first
}
} Try / catch
var pe *fs.PathError
if errors.As(err, &pe) || strings.Contains(err.Error(), "not found and") {
// surface a friendly 'install <interpreter>' message
} Prevention
- Lint shebangs in CI against a matrix of target machines.
- Avoid absolute interpreter paths in shared scripts; use env form.
- Document required interpreters per project and verify at bootstrap.
- Keep interpreter installs and PATH in infrastructure-as-code.
When it happens
Trigger: A script's shebang uses a full path (contains '/' or '\'), e.g. `#!/usr/local/bin/python3`; os.Stat returns fs.ErrNotExist (so EACCES etc. are surfaced elsewhere), and exec.LookPath("python3") also fails. Raised by dispatchShebang for every such script.
Common situations: Scripts copied between machines where the interpreter lives at different paths; Docker images without /usr/local/bin/python3; Windows hosts lacking any PATH-resolvable bash for `#!/bin/bash`; uninstalling an interpreter after scripts referencing it were authored.
Related errors
- interpreter %q not found in PATH
- empty shebang
- env: missing program name
- env -S requires a program
- unsupported env flag: %s
AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29).
Data as JSON: /api/errors/73e37321de041d09.
Report an issue: GitHub.