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

  1. Ensure git is installed and on PATH for the daemon process (`git --version`).
  2. For slow repos, reduce git.summary scope (lower maxCommits) or run refresh when the repo is less busy.
  3. If git output exceeds the buffer, trim the repo history or avoid git.summary on very large repos.
  4. 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

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


AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12). Data as JSON: /api/errors/a4a3a9d4e4f3ad4e. Report an issue: GitHub.