jarrodwatts/claude-hud · critical · Error
Unable to resolve an absolute git.exe from PATH
Error message
Unable to resolve an absolute git.exe from PATH
What it means
On Windows, WindowsGitRunner spawns a detached worker process with shell:false and an absolute path to git.exe, so it never relies on PATH lookup at spawn time. During construction it calls resolveWindowsGitExecutable(), which scans every absolute entry of the PATH environment variable for a git.exe that exists and is a regular file (src/git-runner.ts:289-312). If no such entry is found, the constructor throws 'Unable to resolve an absolute git.exe from PATH' — the library refuses to run because the worker could not launch git.
Source
Thrown at src/git-runner.ts:92
return { stdout };
}
async close(): Promise<void> {
// Direct commands have no session process to release.
}
}
class WindowsGitRunner implements GitCommandRunner {
private readonly worker: ChildProcess;
private nextId = 1;
private pending: PendingCommand | null = null;
private exited = false;
private closing = false;
constructor(private readonly cwd: string) {
const workerPath = fileURLToPath(new URL('./windows-git-worker.js', import.meta.url));
const gitExecutable = resolveWindowsGitExecutable();
if (!gitExecutable) throw new Error('Unable to resolve an absolute git.exe from PATH');
this.worker = spawn(process.execPath, [workerPath, gitExecutable], {
env: createGitEnvironment(),
windowsHide: true,
shell: false,
stdio: ['ignore', 'ignore', 'ignore', 'ipc'],
});
this.worker.on('message', (message: unknown) => this.handleMessage(message));
this.worker.once('error', (error) => this.failPending(error));
this.worker.once('exit', (code, signal) => {
this.exited = true;
if (!this.closing) {
this.failPending(new Error(`Git worker exited unexpectedly (${signal ?? code ?? 'unknown'})`));
}
});
}
View on GitHub (pinned to 939eb66485)
Solutions
- Install Git for Windows (or point PATH at an existing install's cmd directory, e.g. C:\Program Files\Git\cmd) and restart the shell/process so PATH is picked up.
- Verify with 'where git.exe' in cmd (or 'Get-Command git.exe' in PowerShell) that git.exe resolves via an absolute PATH entry; fix PATH ordering/entries if not.
- If PATH is intentionally sanitized, set a PATH environment variable containing the absolute directory of git.exe before constructing the runner.
- Use a machine where git.exe exists on disk at an absolute path; relative PATH directories are deliberately ignored by the resolver for security (repo-controlled lookups).
- As a last resort, patch/extend the environment passed to the runner so PATH includes the Git cmd directory (createGitEnvironment preserves PATH-based resolution).
Example fix
// before (no git.exe reachable from PATH) const runner = new WindowsGitRunner(repoCwd); // throws // after (ensure PATH includes Git before constructing) process.env.PATH = ['C:\\Program Files\\Git\\cmd', process.env.PATH].join(path.win32.delimiter); const runner = new WindowsGitRunner(repoCwd);
Defensive patterns
Strategy: try-catch
Validate before calling
import { resolveWindowsGitExecutable } from './src/git-runner.js';
function canConstructWindowsGitRunner(): boolean {
return resolveWindowsGitExecutable() !== null;
}
if (!canConstructWindowsGitRunner()) {
// fix PATH / install Git before proceeding
} Type guard
function hasGitExecutable(
resolveCandidate: (c: string) => string | null = (c) => {
try { const r = require('fs').realpathSync(c); return require('fs').statSync(r).isFile() ? r : null; } catch { return null; }
},
): boolean {
return resolveWindowsGitExecutable(process.env, resolveCandidate) !== null;
} Try / catch
let runner: WindowsGitRunner;
try {
runner = new WindowsGitRunner(cwd);
} catch (err) {
if (err instanceof Error && err.message.includes('Unable to resolve an absolute git.exe')) {
// fall back: report missing Git, or use a different runner / disable git features
throw new Error('Git for Windows not found on PATH; install it or fix PATH.', { cause: err });
}
throw err;
} Prevention
- In installation/setup docs, require Git for Windows and verify 'where git.exe' resolves during bootstrap.
- Check resolveWindowsGitExecutable() at app startup and surface a clear setup error before any runner construction.
- Never sanitize PATH to only relative directories when spawning tooling; always keep absolute Git cmd directory entries.
- In CI/service contexts, explicitly set PATH to include the Git installation directory rather than relying on inherited environment.
- Prefer absolute Git paths passed via environment/config over relying on PATH lookup.
When it happens
Trigger: Constructing WindowsGitRunner (new WindowsGitRunner(cwd)) on Windows when resolveWindowsGitExecutable returns null: (1) PATH env var is unset or empty; (2) PATH contains only relative entries (entries that are not path.win32.isAbsolute are skipped); (3) no PATH entry contains git.exe, or the git.exe candidate fails statSync/isFile (e.g. Git not installed, or only git.cmd/git-wrapper present); (4) PATH entries contain embedded NUL characters or fail realpathSync.
Common situations: Git for Windows not installed or installed in a non-PATH location (e.g. portable Git); running under a service/CI account whose PATH lacks the usual 'C:\Program Files\Git\cmd'; PATH stripped or overridden by a sanitized environment (spawn env customization, containers, GUI-launched apps inheriting minimal PATH); Git exposed only as git.exe via a shell alias or via git.cmd in cmd/ with an older layout where git.exe sits elsewhere; corrupted PATH with quoted or malformed entries.
AI-assisted analysis of jarrodwatts/claude-hud@939eb66485 (2026-08-29).
Data as JSON: /api/errors/074305a389595c3e.
Report an issue: GitHub.