affaan-m/ECC · error · Error

Failed to run gh: ${result.error.message}

Error message

Failed to run gh: ${result.error.message}

What it means

Thrown by scripts/runGhJson in scripts/work-items.js when Node's spawnSync returns an error object (result.error set) instead of a process result. This happens when the `gh` executable cannot be spawned at all — most commonly because the GitHub CLI is not installed, not on PATH, or (when ECC_GH_SHIM is set) the shim path is invalid. It is an environment-level failure, not a GitHub API failure.

Source

Thrown at scripts/work-items.js:156

  const parsed = Number.parseInt(value, 10);
  if (!Number.isFinite(parsed) || parsed <= 0) {
    throw new Error(`Invalid limit: ${value}`);
  }
  return parsed;
}

function runGhJson(args) {
  const shimPath = process.env.ECC_GH_SHIM;
  const command = shimPath ? process.execPath : 'gh';
  const commandArgs = shimPath ? [shimPath, ...args] : args;
  const displayCommand = shimPath ? `node ${shimPath} ${args.join(' ')}` : `gh ${args.join(' ')}`;
  const result = spawnSync(command, commandArgs, {
    encoding: 'utf8',
    maxBuffer: 10 * 1024 * 1024
  });

  if (result.error) {
    throw new Error(`Failed to run gh: ${result.error.message}`);
  }

  if (result.status !== 0) {
    throw new Error(`${displayCommand} failed: ${(result.stderr || result.stdout || '').trim()}`);
  }

  try {
    return JSON.parse(result.stdout || '[]');
  } catch (error) {
    throw new Error(`${displayCommand} returned invalid JSON: ${error.message}`);
  }
}

function slugifyWorkItemSegment(value) {
  return (
    String(value || '')
      .toLowerCase()
      .replace(/[^a-z0-9]+/g, '-')

View on GitHub (pinned to 01e15490f0)

Solutions

  1. Install the GitHub CLI (e.g. `brew install gh`, `apt install gh`, or see https://cli.github.com) and confirm `which gh` resolves.
  2. Authenticate with `gh auth login` (a missing auth causes a different error — error 478 — but confirming gh is present is step one).
  3. If using ECC_GH_SHIM, verify the shim file path exists and is executable.
  4. In CI, add an explicit gh installation step and a `gh --version` smoke check before invoking sync-github.

Example fix

// before
node scripts/work-items.js sync-github --repo owner/repo
# Error: Failed to run gh: spawn gh ENOENT

// after
brew install gh
gh auth login
node scripts/work-items.js sync-github --repo owner/repo
Defensive patterns

Strategy: validation

Validate before calling

const { spawnSync } = require('child_process');
function ghAvailable() {
  const r = spawnSync('gh', ['--version'], { encoding: 'utf8' });
  return r.status === 0 && /gh version/.test(r.stdout || '');
}
if (!ghAvailable()) {
  throw new Error('GitHub CLI (gh) is required for sync-github. Install from https://cli.github.com');
}

Try / catch

// retry once after a short delay if gh spawn fails transiently
async function runSyncGithubWithRetry(args, retries = 1) {
  for (let attempt = 0; attempt <= retries; attempt++) {
    try {
      return runWorkItems(args);
    } catch (e) {
      if (attempt === retries || !/Failed to run gh/.test(e.message)) throw e;
      await new Promise(r => setTimeout(r, 2000));
    }
  }
}

Prevention

When it happens

Trigger: Running `node scripts/work-items.js sync-github --repo owner/repo` on a machine without `gh` installed; CI image that lacks the gh CLI; ECC_GH_SHIM pointing to a nonexistent file; gh present but not executable (permissions).

Common situations: Fresh dev machine or minimal Docker image without gh; a CI runner that installs gh conditionally and skipped it; setting ECC_GH_SHIM to a test shim that was since deleted.

Related errors


AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13). Data as JSON: /api/errors/bdb6e70ad9454b15. Report an issue: GitHub.