{"record":{"id":"35f3224247d0c747","repo":"affaan-m/ECC","slug":"invalid-repo-format-repo-expected-owner-re","errorCode":null,"errorMessage":"Invalid repo format: \"${repo}\". Expected \"owner/repo\".","messagePattern":"Invalid repo format: \"(.+?)\"\\. Expected \"owner/repo\"\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/lib/github-coordination/gh-api.js","lineNumber":8,"sourceCode":"'use strict';\n\nconst { spawnSync } = require('child_process');\n\nfunction normalizeRepo(repo) {\n  const parts = String(repo || '').split('/').filter(Boolean);\n  if (parts.length !== 2) {\n    throw new Error(`Invalid repo format: \"${repo}\". Expected \"owner/repo\".`);\n  }\n  const [owner, name] = parts;\n  return { owner, name };\n}\n\nfunction normalizeIssueNumber(value) {\n  const parsed = Number.parseInt(String(value), 10);\n  if (!Number.isFinite(parsed) || parsed <= 0) {\n    throw new Error(`Invalid issue number: ${value}`);\n  }\n  return parsed;\n}\n\nfunction normalizeLabelValue(label) {\n  if (typeof label === 'string') {\n    return label.trim();\n  }\n  if (label && typeof label === 'object') {","sourceCodeStart":1,"sourceCodeEnd":26,"githubUrl":"https://github.com/affaan-m/ECC/blob/01e15490f04e29cfefe3896951f43db46994d8ee/scripts/lib/github-coordination/gh-api.js#L1-L26","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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."],"exampleFix":"// before\ngetIssue('https://github.com/acme/widgets', 42);\n\n// after — extract owner/name from any GitHub reference\nfunction toOwnerName(input) {\n  if (/^[\\w.-]+\\/[\\w.-]+$/.test(input)) return input;\n  const u = new URL(input.includes('://') ? input : `https://github.com/${input}`);\n  return u.pathname.replace(/^\\//, '').replace(/\\.git$/, '').replace(/\\/$/, '');\n}\ngetIssue(toOwnerName(raw), 42);","handlingStrategy":"validation","validationCode":"const parts = String(repo || '').split('/').filter(Boolean);\nif (parts.length !== 2) {\n  throw new Error(`repo must be 'owner/name', got ${JSON.stringify(repo)}`);\n}","typeGuard":"function isOwnerName(repo) {\n  return /^[\\w.-]+\\/[\\w.-]+$/.test(String(repo || ''));\n}","tryCatchPattern":"try {\n  getIssue(repo, issueNumber);\n} catch (e) {\n  if (/Invalid repo format/.test(e.message)) { console.error('Pass repo as owner/name'); process.exit(2); }\n  throw e;\n}","preventionTips":["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."],"tags":["github-coordination","gh-api","validation","repo-format"],"backgroundTag":null,"analyzedSha":"01e15490f04e29cfefe3896951f43db46994d8ee","analyzedAt":"2026-08-13T00:31:08.655Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}