affaan-m/ECC · error

failed

Error message

${command} ${args.join(' ')} failed: ${result.error.message}

What it means

runCommand spawns a child process (gh or a shim) and throws when the spawn itself errored (result.error is set), meaning the command could not be executed at all — the process never ran to completion. This is distinct from a non-zero exit code (error 212). Typical result.error causes are ENOENT (binary not found), EACCES (not executable), or the process being killed.

Solutions

  1. Install the GitHub CLI (e.g. brew install gh) and verify with `gh --version`.
  2. Ensure gh is on the PATH of the environment running the script (check options.env / process.env.PATH).
  3. If using ECC_GH_SHIM, verify the shim file exists and is executable (chmod +x).
  4. Re-run the command; transient kills (signals/OOM) may just need a retry.

Example fix

// before
runGh(['issue', 'view', '123']) // throws: gh issue view 123 failed: spawn gh ENOENT
// after
if (!fs.existsSync(shimPath || 'gh')) throw new Error('gh CLI not found; install GitHub CLI first');
runGh(['issue', 'view', '123']);
Defensive patterns

Strategy: try-catch

Validate before calling

const cmd = process.env.ECC_GH_SHIM || 'gh';
const which = require('child_process').spawnSync(cmd, ['--version'], { stdio: 'ignore' });
if (which.error) throw new Error(`'${cmd}' is not installed/executable; install GitHub CLI`);

Type guard

null

Try / catch

try {
  const out = runGh(args);
} catch (e) {
  if (/failed: spawn .* ENOENT/.test(e.message)) {
    console.error('gh CLI not found. Install it: https://cli.github.com/');
  } else {
    throw e;
  }
}

Prevention

When it happens

Trigger: Calling runGh (and thus runCommand) when the gh binary is not installed or not on PATH, the ECC_GH_SHIM path points at a missing/non-executable file, or the process is killed by a signal.

Common situations: Fresh machines where GitHub CLI was never installed (gh: command not found / ENOENT), a shim path typo in ECC_GH_SHIM, wrong file permissions on a custom shim, or OOM/signals killing the child.

Related errors


AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16). Data as JSON: /api/errors/9f203770f764bca1. Report an issue: GitHub.

Appendix: source

Thrown at scripts/lib/github-coordination/gh-api.js:45

    return String(label.name || label.label || '').trim();
  }
  return '';
}

function normalizeLabels(labels) {
  return Array.from(new Set((Array.isArray(labels) ? labels : []).map(normalizeLabelValue).filter(Boolean))).sort();
}

function runCommand(command, args, options = {}) {
  const result = spawnSync(command, args, {
    cwd: options.cwd,
    env: options.env || process.env,
    encoding: 'utf8',
    maxBuffer: 10 * 1024 * 1024,
  });

  if (result.error) {
    throw new Error(`${command} ${args.join(' ')} failed: ${result.error.message}`);
  }

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

  return result.stdout || '';
}

// ECC_GH_SHIM creates a trust boundary: when set, shimPath replaces the real
// `gh` binary and command/commandArgs execute an arbitrary script via
// process.execPath. This variable MUST only be set in trusted, isolated test
// environments (e.g., a test's own temp directory). Never set ECC_GH_SHIM in
// production — doing so allows arbitrary script execution under the caller's
// privileges.
function runGh(args, options = {}) {
  const shimPath = process.env.ECC_GH_SHIM;
  const command = shimPath ? process.execPath : 'gh';

View on GitHub (pinned to 8321021c54)