Yeachan-Heo/oh-my-codex · error · Error

${stderr || MISSION_DIR_GIT_ERROR}

Error message

${stderr || MISSION_DIR_GIT_ERROR}

What it means

Thrown by readGit in src/autoresearch/contracts.ts when a git subprocess it runs (e.g. git rev-parse --show-toplevel) fails. The error message is the trimmed stderr from git if available, otherwise the generic MISSION_DIR_GIT_ERROR message. This surfaces git invocation failures such as not being inside a repository or git not being installed.

Source

Thrown at src/autoresearch/contracts.ts:63

  return new Error(message);
}

function readGit(repoPath: string, args: string[]): string {
  try {
    return execFileSync('git', args, {
      cwd: repoPath,
      encoding: 'utf-8',
      stdio: ['ignore', 'pipe', 'pipe'],
      windowsHide: true,
    }).trim();
  } catch (error) {
    const err = error as NodeJS.ErrnoException & { stderr?: string | Buffer };
    const stderr = typeof err.stderr === 'string'
      ? err.stderr.trim()
      : err.stderr instanceof Buffer
        ? err.stderr.toString('utf-8').trim()
        : '';
    throw contractError(stderr || MISSION_DIR_GIT_ERROR);
  }
}

export function slugifyMissionName(value: string): string {
  return value
    .toLowerCase()
    .replace(/[^a-z0-9]+/g, '-')
    .replace(/-+/g, '-')
    .replace(/^-|-$/g, '')
    .slice(0, 48) || 'mission';
}

function ensurePathInside(parentPath: string, childPath: string): void {
  const rel = relative(parentPath, childPath);
  if (rel === '' || (!rel.startsWith('..') && rel !== '..')) return;
  throw contractError(MISSION_DIR_GIT_ERROR);
}

View on GitHub (pinned to 3ad79a8a6f)

Solutions

  1. Verify the mission directory is inside a git repository: run git rev-parse --show-toplevel in it.
  2. If git is missing, install git or ensure it is on PATH for the process.
  3. If git printed stderr (e.g. 'detected dubious ownership'), fix accordingly — e.g. git config --global --add safe.directory <path>.
  4. Initialize a repo (git init) if the mission folder was meant to be standalone.

Example fix

// before
const contract = await loadAutoresearchMissionContract('/plain/folder/mission');

// after
await exec('git -C /plain/folder init'); // or move mission inside an existing repo
const contract = await loadAutoresearchMissionContract('/plain/folder/mission');
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 assertGitRepoAvailable(dir: string): Promise<void> {
  await execFileAsync('git', ['-C', dir, 'rev-parse', '--show-toplevel'], { timeout: 5000 });
}

Try / catch

try {
  const contract = await loadAutoresearchMissionContract(missionDir);
} catch (err) {
  const msg = err instanceof Error ? err.message : String(err);
  if (msg.includes('git') || msg === MISSION_DIR_GIT_ERROR) {
    // surface git stderr, suggest git init / PATH / safe.directory fixes
  }
  throw err;
}

Prevention

When it happens

Trigger: loadAutoresearchMissionContract -> readGit(missionDir, ['rev-parse','--show-toplevel']) when the mission directory is not inside a git work tree, git is not on PATH, or git exits non-zero for another reason (permissions, corrupt repo).

Common situations: Pointing --mission-dir at a plain folder that was never git-inited; running in a container/CI image without git; a .git directory with broken ownership ('dubious ownership' safe.directory errors).

Related errors


AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27). Data as JSON: /api/errors/eca7cab42dd9da6e. Report an issue: GitHub.