affaan-m/ECC · error · Error
Invalid repo: ${repo}
Error message
Invalid repo: ${repo} What it means
Thrown by splitRepo() in scripts/lib/github-discussions.js when the repo argument cannot be split into a non-empty owner and name on the '/' separator. The function underlies all GraphQL discussion lookups, which require both owner and name variables.
Source
Thrown at scripts/lib/github-discussions.js:13
'use strict';
const { spawnSync } = require('child_process');
const DEFAULT_DISCUSSION_FIRST = 100;
const MAINTAINER_ASSOCIATIONS = new Set(['OWNER', 'MEMBER', 'COLLABORATOR']);
const DISCUSSION_ENABLED_QUERY = 'query($owner: String!, $name: String!) { repository(owner: $owner, name: $name) { hasDiscussionsEnabled } }';
const DISCUSSION_QUERY = 'query($owner: String!, $name: String!, $first: Int!) { repository(owner: $owner, name: $name) { hasDiscussionsEnabled discussions(first: $first, orderBy: {field: UPDATED_AT, direction: DESC}) { totalCount nodes { number title url updatedAt authorAssociation category { name isAnswerable } answer { url authorAssociation } comments(first: 20) { nodes { authorAssociation } } } } } }';
function splitRepo(repo) {
const [owner, name] = String(repo || '').split('/');
if (!owner || !name) {
throw new Error(`Invalid repo: ${repo}`);
}
return { owner, name };
}
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()}`);View on GitHub (pinned to 01e15490f0)
Solutions
- Pass the repo in owner/name form: 'affaan-m/ECC'.
- If reading from an env var, validate and default it: const repo = process.env.GH_REPO; if (!repo || repo.split('/').length !== 2) throw ...
- Trim and strip a trailing slash before splitting.
Example fix
// before
fetchDiscussionSummary('ECC');
// after
fetchDiscussionSummary('affaan-m/ECC');
// or guard:
function safeSplit(repo) {
const parts = String(repo || '').trim().replace(/\/+$/, '').split('/');
if (parts.length !== 2 || !parts[0] || !parts[1]) {
throw new Error(`Invalid repo: ${repo}`);
}
return { owner: parts[0], name: parts[1] };
} Defensive patterns
Strategy: type-guard
Validate before calling
function parseRepo(repo) {
const parts = String(repo || '').trim().replace(/\/+$/, '').split('/');
if (parts.length !== 2 || !parts[0] || !parts[1]) {
throw new Error(`Invalid repo: ${repo}`);
}
return { owner: parts[0], name: parts[1] };
}
const { owner, name } = parseRepo(process.env.GH_REPO); Type guard
function isOwnerSlashName(v) {
return typeof v === 'string'
&& /^\S+\/\S+$/.test(v.trim())
&& !v.trim().endsWith('/');
} Try / catch
try {
return splitRepo(repo);
} catch (err) {
if (/Invalid repo/.test(err.message)) {
throw new Error(`GH_REPO must be 'owner/name'; got '${repo}'`);
}
throw err;
} Prevention
- Always source repo from a validated config or env var with an owner/name pattern check.
- Strip trailing slashes and whitespace at the boundary, not deep inside.
- Add a unit test covering 'owner/name', 'owneronly', '', undefined.
When it happens
Trigger: splitRepo(repo) called with undefined, null, '', 'owneronly', '/name', 'owner/', or any string without exactly one slash-delimited non-empty segment on each side.
Common situations: Caller passed the bare repo name (e.g. 'ECC') instead of 'affaan-m/ECC'; env var GH_REPO unset so undefined reaches the call; extra whitespace produced an empty segment after trim; user typed owner/name with a trailing slash.
Related errors
- Refusing to run install from untrusted repo root ${normalize
- Unknown argument: ${arg}
- Missing issue number.
- Missing --repo <owner/repo>.
- At least one guided harness must be selected
AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13).
Data as JSON: /api/errors/bee4c97a873a06e1.
Report an issue: GitHub.