JuliusBrussee/caveman · error · Error

caveman-code: multiple provider credentials found; set CAVE_

Error message

caveman-code: multiple provider credentials found; set CAVE_MODEL to pick one

What it means

The credential-based default picks a provider only when the choice is unambiguous. If two or more of ANTHROPIC_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY/GOOGLE_API_KEY are present, the agent refuses to guess which provider you meant and asks for an explicit CAVE_MODEL.

Source

Thrown at packages/agent/src/code.ts:562

}

function resolveCodingModelID(explicit: string | undefined): string {
  const requested = explicit ?? process.env.CAVE_MODEL;
  if (requested !== undefined && requested !== "") {
    const slash = requested.indexOf("/");
    if (slash <= 0 || slash === requested.length - 1) {
      throw new Error("caveman-code: model must use provider/model format");
    }
    return requested;
  }
  const configured: string[] = [];
  if (process.env.ANTHROPIC_API_KEY) configured.push("anthropic/claude-sonnet-4-6");
  if (process.env.OPENAI_API_KEY) configured.push("openai/gpt-5.5");
  if (process.env.GEMINI_API_KEY || process.env.GOOGLE_API_KEY) {
    configured.push("google/gemini-2.5-pro");
  }
  if (configured.length !== 1) {
    throw new Error(
      configured.length === 0
        ? "caveman-code: no supported provider credential found; set ANTHROPIC_API_KEY, OPENAI_API_KEY, or GEMINI_API_KEY"
        : "caveman-code: multiple provider credentials found; set CAVE_MODEL to pick one",
    );
  }
  return configured[0]!;
}

// ---------------------------------------------------------------------------
// Session
// ---------------------------------------------------------------------------

export type SessionMode = "optimized" | "observe-only";

export interface CodingSessionOptions {
  conversation?: ConversationState;
  cave?: "auto" | "off";
  gatewayURL?: string;

View on GitHub (pinned to 27d5a3981a)

Solutions

  1. Set CAVE_MODEL to the provider/model you want, e.g. `export CAVE_MODEL=anthropic/claude-sonnet-4-6`
  2. Or unset the credentials you do not want used this run: `unset OPENAI_API_KEY GEMINI_API_KEY GOOGLE_API_KEY`
  3. Scope secrets per-project (direnv, .env per repo) so only one provider's key is present

Example fix

# before: ambiguous
export ANTHROPIC_API_KEY=...
export OPENAI_API_KEY=...

# after: disambiguate
export CAVE_MODEL="anthropic/claude-sonnet-4-6"
Defensive patterns

Strategy: validation

Validate before calling

const groups = [
  ["ANTHROPIC_API_KEY"],
  ["OPENAI_API_KEY"],
  ["GEMINI_API_KEY", "GOOGLE_API_KEY"],
] as const;
const active = groups.filter((g) => g.some((v) => process.env[v] && process.env[v] !== ""));
if (active.length > 1 && !process.env.CAVE_MODEL) {
  throw new Error(`ambiguous credentials (${active.length} providers); set CAVE_MODEL`);
}

Prevention

When it happens

Trigger: Having e.g. both ANTHROPIC_API_KEY and OPENAI_API_KEY in the environment (common on dev machines with multiple provider CLIs installed) while CAVE_MODEL is unset.

Common situations: Developer shells with accumulative .envrc/.zshrc exports; CI templates that inject all available secrets 'just in case'; shared machines where different projects use different providers.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15). Data as JSON: /api/errors/ecfb5c72d7eb1c29. Report an issue: GitHub.