JuliusBrussee/caveman · error · Error

multiple provider credentials detected; pass --provider

Error message

multiple provider credentials detected; pass --provider

What it means

When credentials for more than one provider are present in the environment and stdio is not a TTY, chooseProvider cannot disambiguate and cannot prompt interactively, so it throws asking for an explicit --provider choice.

Solutions

  1. Pass --provider with the desired value to disambiguate
  2. Temporarily unset the extra keys (`unset OPENAI_API_KEY`) so only one is detected
  3. In CI, scope secrets to just the provider you intend to use
  4. Run interactively in a TTY, where a prompt lets you pick instead of throwing

Example fix

// before
npm create @caveman-ai/agent@latest my-app   # both ANTHROPIC_API_KEY and OPENAI_API_KEY set, non-TTY
// after
npm create @caveman-ai/agent@latest my-app -- --provider openai
Defensive patterns

Strategy: validation

Validate before calling

const keys = ["ANTHROPIC_API_KEY", "OPENAI_API_KEY", "GEMINI_API_KEY", "GOOGLE_API_KEY"]
  .filter(k => Boolean(process.env[k]));
if (keys.length > 1 && !process.argv.includes("--provider")) {
  process.argv.push("--provider", "anthropic"); // disambiguate before running
}

Type guard

function exactlyOneProviderCredential(): boolean {
  return ["ANTHROPIC_API_KEY", "OPENAI_API_KEY", "GEMINI_API_KEY", "GOOGLE_API_KEY"]
    .filter(k => Boolean(process.env[k])).length === 1;
}

Try / catch

try {
  await main();
} catch (error) {
  if (error instanceof Error && error.message.includes("multiple provider credentials")) {
    console.error("Multiple provider keys detected; pass --provider to choose one");
    process.exitCode = 1;
  } else throw error;
}

Prevention

When it happens

Trigger: Two or more of ANTHROPIC_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY/GOOGLE_API_KEY are set simultaneously and the command runs non-interactively (CI, piped output, script).

Common situations: Developers with keys for several providers in their shell profile running the scaffolder from a script; CI runners that export multiple vendor keys globally; leftover keys from previous experiments.

Understand the failure class

Background: "--flag is required" and "must specify" CLI errors: how missing-required-flag validation works and how to fix it — this error's family across 20 libraries.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20). Data as JSON: /api/errors/f895c19d00e13f0a. Report an issue: GitHub.

Appendix: source

Thrown at packages/create-caveman-agent/src/index.ts:139

    "TEMP", "TMP", "TMPDIR", "LANG", "LC_ALL", "LC_CTYPE", "TZ", "CI", "NO_COLOR", "FORCE_COLOR",
    "HTTP_PROXY", "HTTPS_PROXY", "NO_PROXY", "http_proxy", "https_proxy", "no_proxy",
    "NPM_CONFIG_CACHE", "NPM_CONFIG_REGISTRY", "NPM_CONFIG_USERCONFIG",
    "npm_config_cache", "npm_config_registry", "npm_config_userconfig",
  ]) {
    if (process.env[key] !== undefined) env[key] = process.env[key];
  }
  return env;
}

async function chooseProvider(flag: string | undefined): Promise<Provider> {
  if (flag !== undefined) return parseProvider(flag);
  const detected: Provider[] = [];
  if (process.env.ANTHROPIC_API_KEY) detected.push("anthropic");
  if (process.env.OPENAI_API_KEY) detected.push("openai");
  if (process.env.GEMINI_API_KEY || process.env.GOOGLE_API_KEY) detected.push("google");
  if (detected.length === 1) return detected[0]!;
  if (!process.stdin.isTTY || !process.stdout.isTTY) {
    throw new Error(
      detected.length === 0
        ? "no provider credential detected; pass --provider"
        : "multiple provider credentials detected; pass --provider",
    );
  }
  const rl = createInterface({ input: process.stdin, output: process.stdout });
  try {
    const answer = await rl.question("Provider (anthropic/openai/google): ");
    return parseProvider(answer);
  } finally {
    rl.close();
  }
}

function projectFiles(name: string, provider: Provider): Record<string, string> {
  return {
    "package.json": `${JSON.stringify({
      name,

View on GitHub (pinned to 3ee70a1026)