nexu-io/open-design · error
git command failed
Error message
git command failed
What it means
runGit (refresh.ts:610-622) runs `git` via execFileAsync with a 10s timeout and 128 KiB buffer. Exit code 128 is treated as the benign 'not a git repo / expected git error' case and returns ''. Any other failure surfaces stderr (trimmed), then the error message, then the literal fallback 'git command failed'.
Source
Thrown at apps/daemon/src/live-artifacts/refresh.ts:621
parsed = JSON.parse(await readFile(targetReal, 'utf8')) as BoundedJsonValue;
} catch {
throw new Error(`project_files.read_json could not parse JSON at ${filePath}`);
}
return asBoundedRefreshOutput({ toolName: 'project_files.read_json', path: filePath, size: entryStat.size, json: parsed });
}
function compactExecOutput(value: string): string[] {
return value.split('\n').map((line) => line.trimEnd()).filter(Boolean).slice(0, 100);
}
async function runGit(projectPath: string, args: string[], signal: AbortSignal | undefined): Promise<string> {
try {
const result = await execFileAsync('git', args, { cwd: projectPath, signal, timeout: 10_000, maxBuffer: 128 * 1024 });
return result.stdout.toString();
} catch (error) {
const maybeError = error as { stdout?: string | Buffer; stderr?: string | Buffer; message?: string; code?: unknown };
if (maybeError.code === 128) return '';
throw new Error(maybeError.stderr?.toString().trim() || maybeError.message || 'git command failed');
}
}
async function executeGitSummary(options: ExecuteLocalDaemonRefreshSourceOptions): Promise<BoundedJsonObject> {
const input = options.source.input as GitSummaryInput;
const maxCommits = optionalPositiveInteger(input.maxCommits, 'input.maxCommits', 10, 50);
const dir = projectDir(options.projectsRoot, options.projectId);
const insideWorkTree = (await runGit(dir, ['rev-parse', '--is-inside-work-tree'], options.signal)).trim() === 'true';
if (!insideWorkTree) return asBoundedRefreshOutput({ toolName: 'git.summary', isRepository: false, branch: '', status: [], recentCommits: [], diffStat: [] });
const [branch, status, recentCommits, diffStat] = await Promise.all([
runGit(dir, ['branch', '--show-current'], options.signal),
runGit(dir, ['status', '--short'], options.signal),
runGit(dir, ['log', `--max-count=${maxCommits}`, '--pretty=format:%h %s'], options.signal),
runGit(dir, ['diff', '--stat', '--', '.'], options.signal),
]);
return asBoundedRefreshOutput({View on GitHub (pinned to 5be4028344)
Solutions
- Ensure git is installed and on PATH for the daemon process (`git --version`).
- For slow repos, reduce git.summary scope (lower maxCommits) or run refresh when the repo is less busy.
- If git output exceeds the buffer, trim the repo history or avoid git.summary on very large repos.
- Check the refresh log for the actual stderr/message when present; this literal message only appears when both are empty.
Example fix
// before: git missing from the daemon's PATH
// runGit throws `git command failed`
// after: ensure git is resolvable
// export PATH="$PATH:/usr/bin" (or install git in the container)
// verify: node -e "require('child_process').execFile('git',['--version'],(e,o)=>console.log(e,o))" Defensive patterns
Strategy: try-catch
Validate before calling
import { execFile } from 'node:child_process';
import { promisify } from 'node:util';
const execFileAsync = promisify(execFile);
async function gitAvailable(): Promise<boolean> {
try {
await execFileAsync('git', ['--version']);
return true;
} catch {
return false;
}
}
if (!await gitAvailable()) throw new Error('git not found on PATH'); Try / catch
try {
await runGit(dir, ['rev-parse', '--is-inside-work-tree'], signal);
} catch (err) {
const e = err as { code?: number; stderr?: string };
if (e.code === 128) return; // benign: not a git repo
if (!e.stderr) {
// git missing / timeout / buffer overflow -> 'git command failed'
}
throw err;
} Prevention
- Ensure the git binary is installed and on the daemon's PATH (verify with `git --version` from the daemon env).
- Keep git repos shallow so summary commands stay under the 10s timeout and 128 KiB buffer.
- Log stderr alongside the fallback message so 'git command failed' is diagnosable.
When it happens
Trigger: git fails with a code other than 128 AND stderr/message are empty/missing — e.g. git is not installed (ENOENT), the process is killed by the timeout, the buffer overflows, or git crashes without writing to stderr.
Common situations: git binary missing from PATH (packaged/minimal environments, containers); a git operation exceeding the 10s timeout on a huge repo; output exceeding 128 KiB; permission errors reading .git; signal/abort during refresh.
Related errors
- connector refresh output must be a JSON object
- refresh source ${source.type} is not supported yet
- No refresh source is available yet.
- Refresh is disabled for this artifact source.
- ${firstIssue.path}: ${firstIssue.message}
AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12).
Data as JSON: /api/errors/a4a3a9d4e4f3ad4e.
Report an issue: GitHub.