affaan-m/ECC · error · Error
Invalid repo format: "${repo}". Expected "owner/repo".
Error message
Invalid repo format: "${repo}". Expected "owner/repo". What it means
Thrown by normalizeRepo in gh-api.js when the repo string does not split into exactly two non-empty parts (owner and name) on '/'. All gh CLI calls in this module build --repo owner/name from these parts, so a malformed repo would produce an invalid gh invocation. Empty segments are filtered, so 'a//b' and '/a/b/' both normalize to ['a','b'] and are accepted.
Source
Thrown at scripts/lib/github-coordination/gh-api.js:8
'use strict';
const { spawnSync } = require('child_process');
function normalizeRepo(repo) {
const parts = String(repo || '').split('/').filter(Boolean);
if (parts.length !== 2) {
throw new Error(`Invalid repo format: "${repo}". Expected "owner/repo".`);
}
const [owner, name] = parts;
return { owner, name };
}
function normalizeIssueNumber(value) {
const parsed = Number.parseInt(String(value), 10);
if (!Number.isFinite(parsed) || parsed <= 0) {
throw new Error(`Invalid issue number: ${value}`);
}
return parsed;
}
function normalizeLabelValue(label) {
if (typeof label === 'string') {
return label.trim();
}
if (label && typeof label === 'object') {View on GitHub (pinned to 01e15490f0)
Solutions
- Pass repo strictly as 'owner/name' with exactly one slash and two non-empty segments.
- If you have a URL, extract owner/name first: new URL(remoteUrl).pathname.slice(1).replace(/\/$/, '').
- For SSH remotes (git@github.com:owner/name.git), strip host and .git then split.
- Add a normalizeRepo call at your config-load boundary so downstream code always gets owner/name.
Example fix
// before
getIssue('https://github.com/acme/widgets', 42);
// after — extract owner/name from any GitHub reference
function toOwnerName(input) {
if (/^[\w.-]+\/[\w.-]+$/.test(input)) return input;
const u = new URL(input.includes('://') ? input : `https://github.com/${input}`);
return u.pathname.replace(/^\//, '').replace(/\.git$/, '').replace(/\/$/, '');
}
getIssue(toOwnerName(raw), 42); Defensive patterns
Strategy: validation
Validate before calling
const parts = String(repo || '').split('/').filter(Boolean);
if (parts.length !== 2) {
throw new Error(`repo must be 'owner/name', got ${JSON.stringify(repo)}`);
} Type guard
function isOwnerName(repo) {
return /^[\w.-]+\/[\w.-]+$/.test(String(repo || ''));
} Try / catch
try {
getIssue(repo, issueNumber);
} catch (e) {
if (/Invalid repo format/.test(e.message)) { console.error('Pass repo as owner/name'); process.exit(2); }
throw e;
} Prevention
- Always pass 'owner/name', never a full URL or bare name.
- Convert URLs/remotes to owner/name at the config boundary.
- Validate with a regex before calling gh-api functions.
When it happens
Trigger: Passing repo 'owner' (missing /name), 'owner/name/extra' (three parts), 'a/b/c/d', empty string, or null; a full URL like https://github.com/owner/name (splits into >2 parts).
Common situations: User passed a bare repo name; passed a full GitHub URL instead of owner/name; config stored the SSH/HTTPS remote URL; trailing/extra slashes.
Related errors
- Invalid issue number: ${value}
- invalid repo: expected non-empty string, got ${JSON.stringif
- invalid issueNumber: expected positive integer, got ${JSON.s
- Issue #${issueNumber} is not ready to publish: ${validation.
- ${command} ${args.join(' ')} failed: ${result.error.message}
AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13).
Data as JSON: /api/errors/35f3224247d0c747.
Report an issue: GitHub.