abhigyanpatwari/GitNexus · error

Multiple repositories indexed. Specify which one with the "r

Error message

Multiple repositories indexed. Specify which one with the "repo" parameter. Available: ${labels.join(', ')}

What it means

Repo resolution reached its fallback with no repo parameter supplied while the registry holds multiple repos: there is no single default to choose, so LocalBackend throws and lists all handles (paths added to duplicate names per #829). The caller must disambiguate via the repo parameter — or rely on cwd-based auto-selection, which already had its chance via pickRepoHandleForCwd.

Source

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

    }

    // 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
   *   hot-swaps content without updating `handle.branch`).
   * - `branch` matching an indexed pinned branch → a handle whose

View on GitHub (pinned to aac7515d2a)

Solutions

  1. Add the repo parameter with one of the listed names (or an absolute path for duplicate names).
  2. Or run the client from inside the target repository's directory so cwd-based selection can auto-pick it.
  3. Call list_repos first to enumerate valid handles and their exact labels.
  4. If you only ever work with one repo, consider removing the others from the registry to restore implicit defaulting.

Example fix

# before: ambiguous call, two repos indexed
{"tool": "context", "args": {"name": "parseRepo"}}
# → Multiple repositories indexed. Specify which one with the "repo" parameter. ...

# after: explicit repo (name, or absolute path when names collide)
{"tool": "context", "args": {"name": "parseRepo", "repo": "gitnexus"}}
Defensive patterns

Strategy: validation

Validate before calling

// Make the repo param mandatory in your own client wrapper
async function withRepo<T>(tool: string, args: Record<string, unknown>, cwd: string): Promise<T> {
  if (args.repo) return client.callTool({ name: tool, arguments: args }) as Promise<T>;
  const { repositories } = await client.callTool({ name: 'list_repos', arguments: {} });
  if (repositories.length === 1) return client.callTool({ name: tool, arguments: { ...args, repo: repositories[0].name } }) as Promise<T>;
  const inferred = repositories.find((r: any) => cwd.startsWith(r.repo_path ?? r.path));
  if (!inferred) throw new Error(`Multiple repos indexed (${repositories.length}) — pass repo or run from inside one`);
  return client.callTool({ name: tool, arguments: { ...args, repo: inferred.name } }) as Promise<T>;
}

Try / catch

try {
  return await client.callTool({ name: 'impact', arguments: args });
} catch (err) {
  if (err instanceof Error && err.message.startsWith('Multiple repositories indexed')) {
    const available = err.message.split('Available: ')[1];
    throw new UserChoiceError(`Pick a repo: ${available}`); // surface the choice, never guess
  }
  throw err;
}

Prevention

When it happens

Trigger: Indexing two or more repos (e.g. a CLI package and its web app) and then calling impact/query/context without a repo field from a working directory that is not inside any indexed repo.

Common situations: MCP client configs written when only one repo was indexed, then a second repo gets added; agents running from a neutral directory (home, /tmp) while multiple projects are indexed; shared team MCP servers serving several repos.

Related errors


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