affaan-m/ECC · error · Error

invalid repo: expected non-empty string, got ${JSON.stringif

Error message

invalid repo: expected non-empty string, got ${JSON.stringify(repo)}

What it means

Thrown by assertValidRepo in github-coordination/actions.js when repo is not a non-empty string. Every coordination action (applyClaim, applyPublish, etc.) targets exactly one GitHub repository identified as 'owner/name'; a missing repo makes all downstream gh calls meaningless. This guard runs before any network/spawn so it fails fast.

Source

Thrown at scripts/lib/github-coordination/actions.js:21

const { loadPolicy } = require('./policy');
const { mergeIssueBody, normalizeBodyForComparison } = require('./parsing');
const { getIssue, listIssues, editIssue, commentIssue, normalizeLabels } = require('./gh-api');
const {
  assertIssueClaimable,
  buildIssueComment,
  buildIssueStateFromAction,
  desiredLabelsForState,
  getCoordinationState,
  summarizeStateForOutput,
  syncIssueLabels,
  verifyDependenciesClosed,
} = require('./state');
const { upsertCoordinationWorkItem } = require('./store');
const { extractIssueReferences, extractTasks } = require('./parsing');

function assertValidRepo(repo) {
  if (typeof repo !== 'string' || !repo.trim()) {
    throw new Error(`invalid repo: expected non-empty string, got ${JSON.stringify(repo)}`);
  }
}

function assertValidIssueNumber(issueNumber) {
  if (!Number.isFinite(issueNumber) || issueNumber <= 0 || !Number.isInteger(issueNumber)) {
    throw new Error(`invalid issueNumber: expected positive integer, got ${JSON.stringify(issueNumber)}`);
  }
}

function staleCoordinationLabels(issue, nextLabels, policy) {
  const epicLabel = policy.labels && policy.labels.epic;
  return normalizeLabels(issue.labels).filter(l =>
    (l.startsWith('coordination:') || l === epicLabel) && !nextLabels.includes(l)
  );
}

// applyClaim performs a read (getIssue) → check (assertIssueClaimable) → write
// (editIssue) sequence that is NOT atomic. Two concurrent callers can both read

View on GitHub (pinned to 01e15490f0)

Solutions

  1. Pass repo as a non-empty 'owner/name' string.
  2. Resolve repo from env/config once at startup and fail loudly there if missing: const repo = process.env.GITHUB_REPOSITORY; if (!repo) throw new Error('Set GITHUB_REPOSITORY=owner/name').
  3. Add a CLI --repo required flag with a validator.
  4. Unit-test assertValidRepo with undefined/''/number to lock the guard.

Example fix

// before
applyPublish(repo, issueNumber);

// after — resolve and validate at the boundary
const repo = process.env.GITHUB_REPOSITORY;
if (typeof repo !== 'string' || !repo.trim()) {
  throw new Error('GITHUB_REPOSITORY must be set to owner/name');
}
applyPublish(repo.trim(), issueNumber);
Defensive patterns

Strategy: validation

Validate before calling

if (typeof repo !== 'string' || !repo.trim()) {
  throw new Error('repo must be a non-empty "owner/name" string');
}

Type guard

function isNonEmptyRepoString(repo) {
  return typeof repo === 'string' && repo.trim().length > 0;
}

Try / catch

try {
  applyPublish(repo, issueNumber);
} catch (e) {
  if (/invalid repo/.test(e.message)) { console.error('Set GITHUB_REPOSITORY=owner/name'); process.exit(2); }
  throw e;
}

Prevention

When it happens

Trigger: Calling applyPublish(undefined, 12) or applyPublish('', 12); repo read from an unset env var or a missing config field; repo passed as an object or number by mistake.

Common situations: Env var ECC_REPO / GITHUB_REPOSITORY unset in CI; config file missing the repo key; CLI flag --repo forgotten; programmatic caller destructured wrong field name.

Related errors


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