{"record":{"id":"358ab7b84731cc16","repo":"abhigyanpatwari/GitNexus","slug":"multiple-registered-repos-match-target-lis-358ab7","errorCode":null,"errorMessage":"Multiple registered repos match \"${target}\":\n${listing}\nPass the absolute path instead to disambiguate.","messagePattern":"Multiple registered repos match \"(.+?)\":\n(.+?)\nPass the absolute path instead to disambiguate\\.","errorType":"exception","errorClass":"RegistryAmbiguousTargetError","httpStatus":null,"severity":"error","filePath":"gitnexus/src/storage/repo-manager.ts","lineNumber":1334,"sourceCode":"  // Canonicalising the STORED entry (not just the input) is what gives\n  // us backward-compat for registries written by versions that only\n  // ran `path.resolve` — both get canonicalised here at compare time.\n  const canonicalTarget = canonicalizePath(target);\n  const pathMatch = entries.find((e) => {\n    const a = canonicalizePath(e.path);\n    const b = canonicalTarget;\n    return registryPathEquals(a, b);\n  });\n  if (pathMatch) return pathMatch;\n\n  // Tier 2: name match. Case-insensitive on all platforms — registry\n  // name collisions are already filtered case-insensitively in\n  // `registerRepo`, so \"APP\" vs \"app\" are considered the same key.\n  const targetLower = target.toLowerCase();\n  const nameMatches = entries.filter((e) => e.name.toLowerCase() === targetLower);\n  if (nameMatches.length === 1) return nameMatches[0];\n  if (nameMatches.length > 1) {\n    throw new RegistryAmbiguousTargetError(target, nameMatches);\n  }\n\n  // Tier 3: miss. Build the available-names hint ONCE; resolveRepo-style\n  // disambiguated labels (`app (/path)`) are applied when the same name\n  // appears in multiple entries so the user sees the same hint shape as\n  // `-r <name>` errors.\n  const nameCounts = new Map<string, number>();\n  for (const e of entries) {\n    const key = e.name.toLowerCase();\n    nameCounts.set(key, (nameCounts.get(key) ?? 0) + 1);\n  }\n  const availableNames = entries.map((e) =>\n    (nameCounts.get(e.name.toLowerCase()) ?? 0) > 1 ? `${e.name} (${e.path})` : e.name,\n  );\n  throw new RegistryNotFoundError(target, availableNames);\n};\n\n/**","sourceCodeStart":1316,"sourceCodeEnd":1352,"githubUrl":"https://github.com/abhigyanpatwari/GitNexus/blob/aac7515d2a8c50a1f8f923c6fb77218b333560d6/gitnexus/src/storage/repo-manager.ts#L1316-L1352","documentation":"Target resolution for commands like gitnexus remove resolves tier by tier: canonical path match first (unique by registry construction), then case-insensitive name match. When more than one registry entry carries the requested name — possible after --allow-duplicate-name registrations — the command refuses to guess and throws with a listing of the candidates, telling you to pass the absolute path.","triggerScenarios":"`gitnexus remove app` (or the MCP equivalent target argument) when two entries are registered under name 'app' at different paths.","commonSituations":"Prior --allow-duplicate-name use (upstream + fork, local + CI clone); shared machines where several users' clones got the same default name.","solutions":["Re-run with the absolute repo path — path matches are unique and always win","List registered repos first (gitnexus list / status) and copy the exact path","Prevent recurrence: register duplicates under distinct --name aliases so -r stays unambiguous"],"exampleFix":"# before\ngitnexus remove app    # → ambiguous, two entries named 'app'\n\n# after\ngitnexus remove /home/me/forks/app","handlingStrategy":"validation","validationCode":"const matches = entries.filter(\n  (e) => e.name.toLowerCase() === target.toLowerCase(),\n);\nif (matches.length > 1) {\n  target = matches[0].path; // or surface a picker to the user\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Prefer absolute repo paths as command targets whenever a name might be duplicated","Register duplicates under distinct --name aliases to keep -r unambiguous","Parse the candidate listing from the error to offer the user an explicit choice"],"tags":["registry","cli","ambiguity","disambiguation"],"backgroundTag":"ambiguous-target-resolution","analyzedSha":"aac7515d2a8c50a1f8f923c6fb77218b333560d6","analyzedAt":"2026-08-20T23:29:22.980Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}