JuliusBrussee/caveman · error · Error
no provider credential detected; pass --provider
Error message
no provider credential detected; pass --provider
What it means
chooseProvider auto-detects which LLM provider to use from environment variables (ANTHROPIC_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY/GOOGLE_API_KEY). If none are set AND stdin/stdout is not a TTY (so the interactive picker cannot run), it throws telling you to pass --provider explicitly.
Solutions
- Pass the provider explicitly: `--provider anthropic` (or openai/google)
- Export the matching API key env var (ANTHROPIC_API_KEY, OPENAI_API_KEY, or GEMINI_API_KEY/GOOGLE_API_KEY) before running
- In CI, add the credential to the job's secrets/environment
Example fix
// before (CI, no env) npm create @caveman-ai/agent@latest my-app // after ANTHROPIC_API_KEY=sk-... npm create @caveman-ai/agent@latest my-app // or npm create @caveman-ai/agent@latest my-app -- --provider anthropic
Defensive patterns
Strategy: validation
Validate before calling
const hasProviderEnv = ["ANTHROPIC_API_KEY", "OPENAI_API_KEY", "GEMINI_API_KEY", "GOOGLE_API_KEY"]
.some(k => Boolean(process.env[k]));
if (!hasProviderEnv && !process.stdout.isTTY) {
process.argv.push("--provider", "anthropic"); // pick explicitly in non-interactive contexts
} Type guard
function providerCredentialPresent(): boolean {
return ["ANTHROPIC_API_KEY", "OPENAI_API_KEY", "GEMINI_API_KEY", "GOOGLE_API_KEY"]
.some(k => Boolean(process.env[k]));
} Try / catch
try {
await main();
} catch (error) {
if (error instanceof Error && error.message.includes("no provider credential detected")) {
console.error("Set an API key env var or pass --provider <anthropic|openai|google>");
process.exitCode = 1;
} else throw error;
} Prevention
- In CI/scripts, always pass --provider explicitly
- Export the provider API key in the environment before running
- Remember interactive prompting only works with a real TTY
When it happens
Trigger: No provider env vars are set and the command runs in a non-interactive context: CI pipeline, piped/redirected stdio, non-interactive shell, docker build, or scripted execution with no terminal.
Common situations: Fresh machine where credentials were never exported; CI secrets not configured for the job; running inside Docker or a script where stdin is not a TTY; env vars set only in an interactive shell profile not loaded by the runner.
Understand the failure class
Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.
Related errors
- caveman build: set CAVE_MODEL when zero or multiple…
- multiple provider credentials detected; pass --provider
- CAVE_SETUP_TIMEOUT must be a positive integer
- caveman agent: multiple provider credentials found; set…
- Claude usage refresh needs CAVEMAN_CLAUDE_USAGE_JSON or…
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/0858a33331b6ca41.
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)