abhigyanpatwari/GitNexus · error

Repository "${repoParam}" not found. Available: ${labels.joi

Error message

Repository "${repoParam}" not found. Available: ${labels.join(', ')}

What it means

Repo resolution failed for a caller-supplied repoParam even after refreshing the registry, and at least one other repo IS indexed — so the error enumerates the available handles as a disambiguated list (#829): when two handles share a name, each label is annotated with its repoPath so the caller can pick correctly.

Source

Thrown at gitnexus/src/mcp/local/local-backend.ts:1742

    if (this.repos.size === 0) {
      throw new Error('No indexed repositories. Run: gitnexus analyze');
    }

    // Build a disambiguated "Available: …" list (#829). When two handles
    // share a name, annotate each colliding label with its path so the
    // caller can actually pick the right one. Single-name entries render
    // identically to pre-#829 output.
    const nameCounts = new Map<string, number>();
    for (const h of this.repos.values()) {
      const key = h.name.toLowerCase();
      nameCounts.set(key, (nameCounts.get(key) ?? 0) + 1);
    }
    const labels = [...this.repos.values()].map((h) =>
      (nameCounts.get(h.name.toLowerCase()) ?? 0) > 1 ? `${h.name} (${h.repoPath})` : h.name,
    );

    if (repoParam) {
      throw new Error(`Repository "${repoParam}" not found. Available: ${labels.join(', ')}`);
    }
    throw new Error(
      `Multiple repositories indexed. Specify which one with the "repo" parameter. Available: ${labels.join(', ')}`,
    );
  }

  /**
   * Re-point a resolved repo handle at a specific branch index (#2106).
   *
   * - No `branch` (default) → the flat workspace handle, unchanged (backward
   *   compatible: every existing caller passes no branch).
   * - `branch` equal to the flat slot's **on-disk** recorded branch → the
   *   flat handle. The disk meta is read before any cached state is trusted
   *   (#2364 review F1): the flat slot follows the checked-out working tree
   *   (#2354), so a plain analyze after a branch switch restamps the meta
   *   without any repo-resolution miss that would refresh a long-lived
   *   server's cached handle — the cached label can otherwise serve another
   *   branch's content under the old name (the pool staleness reinit

View on GitHub (pinned to aac7515d2a)

Solutions

  1. Read the 'Available: ...' list in the error (or call list_repos) and pass one of those exact names.
  2. For duplicate names, copy the label's parenthesized absolute path and pass that path as repo.
  3. If the target repo genuinely is not indexed, run `gitnexus analyze` inside it, then retry.
  4. If the repo moved on disk, re-run analyze from its new location so the registry records the current path.

Example fix

# before: stale name after rename
{"tool": "impact", "args": {"target": "oldName:login", "repo": "old-project"}}

# after: use a name from the Available list (or its absolute path)
{"tool": "impact", "args": {"target": "login", "repo": "renamed-project"}}
# duplicate names → disambiguate by path:
{"tool": "impact", "args": {"target": "login", "repo": "/srv/checkouts/a/renamed-project"}}
Defensive patterns

Strategy: validation

Validate before calling

// Validate the repo param against the live registry before tool calls
const { repositories } = await client.callTool({ name: 'list_repos', arguments: {} });
const valid = new Set(repositories.flatMap((r: any) => [r.name, r.repo_path ?? r.path]));

function assertKnownRepo(repoParam: string): void {
  if (!valid.has(repoParam) && !valid.has(repoParam.toLowerCase())) {
    throw new Error(`repo "${repoParam}" not in registry. Known: ${[...valid].join(', ')}`);
  }
}

Type guard

const isKnownRepoHandle = (name: string, repos: Array<{ name: string; repoPath?: string }>): boolean =>
  repos.some((r) => r.name.toLowerCase() === name.toLowerCase() || r.repoPath === name);

Try / catch

try {
  return await client.callTool({ name: 'context', arguments: { ...args, repo } });
} catch (err) {
  if (err instanceof Error && err.message.startsWith('Repository "')) {
    // parse the Available list and re-ask the user / re-resolve the name
    const available = err.message.split('Available: ')[1]?.split(', ') ?? [];
    throw new UserChoiceError(`Unknown repo "${repo}". Pick one of: ${available.join(', ')}`);
  }
  throw err;
}

Prevention

When it happens

Trigger: Passing repo: "myrepo" when the indexed name differs (rename, typo, wrong casing beyond the case-insensitive match), passing an id that no longer exists, or targeting a repo indexed under a different absolute path after it was moved/cloned elsewhere.

Common situations: Hard-coded repo names in MCP client configs drifting after project renames; moving or re-cloning a repo to a new directory so the registered handle no longer matches; multiple machines with different indexed sets; stale docs referencing old repo names.

Related errors


AI-assisted analysis of abhigyanpatwari/GitNexus@aac7515d2a (2026-08-20). Data as JSON: /api/errors/a97caabff799cfed. Report an issue: GitHub.