-
-
Notifications
You must be signed in to change notification settings - Fork 69.3k
Implicit provider auto-discovery silently merges with explicit config — can cause unexpected costs and routing #33327
Description
Summary
When models.providers is explicitly configured, OpenClaw still runs implicit provider auto-detection via environment variables and merges the results into the provider list. This can silently route traffic to unintended providers, cause confusing startup errors, and create cost/compliance surprises.
Behavior
Scenario 1: Confusing startup error
User configures models through a LiteLLM proxy (litellm/bedrock-* model IDs). They set AWS_PROFILE in their shell for an unrelated tool (Claude Code). On openclaw gateway restart:
[bedrock-discovery] Failed to list models: UnrecognizedClientException: The security token included in the request is invalid.
OpenClaw detects AWS_PROFILE and tries native Bedrock model discovery, even though the user routes Bedrock traffic through LiteLLM.
Scenario 2: Silent cost leak
User configures models through a proxy for cost tracking and compliance. They also have ANTHROPIC_API_KEY set in their environment (for another tool, or left over from initial setup). If the proxy goes down or auth fails, resolveApiKeyForProvider() walks the auth chain and finds ANTHROPIC_API_KEY at step 4 (env var fallback) — silently routing traffic directly to the Anthropic API, bypassing the proxy, cost tracking, and audit logging.
Root Cause
resolveProvidersForModelsJson() in src/agents/models-config.ts merges implicit + explicit providers regardless of whether the user has configured explicit providers:
const providers = mergeProviders({
implicit: await resolveImplicitProviders({ agentDir, explicitProviders }),
explicit: explicitProviders
});
// Then ALSO unconditionally adds bedrock and copilot
const implicitBedrock = await resolveImplicitBedrockProvider(...)
if (implicitBedrock) { providers["amazon-bedrock"] = ... }
const implicitCopilot = await resolveImplicitCopilotProvider(...)
if (implicitCopilot) { providers["github-copilot"] = ... }Additionally, resolveApiKeyForProvider() in src/agents/model-selection.ts falls back to env vars at request time:
// Auth resolution order:
// 1. Explicit profile
// 2. Provider auth override from config
// 3. Auth profile store
// 4. Environment variables ← ANTHROPIC_API_KEY, OPENAI_API_KEY, etc. picked up here
// 5. Custom key from models.jsonThis means env vars act as a silent fallback even when the user has configured a specific auth path for a provider.
Scope
This is not limited to Bedrock. resolveImplicitProviders() sniffs 20+ env vars for implicit provider registration:
| Env var | Provider | Startup behavior |
|---|---|---|
AWS_PROFILE / AWS_ACCESS_KEY_ID |
Bedrock | API call (ListFoundationModels) — can error |
GH_TOKEN / GITHUB_TOKEN |
Copilot | API call — can error |
HF_TOKEN |
HuggingFace | Discovery call — can error |
ANTHROPIC_API_KEY |
Anthropic | Passive (silent fallback at request time) |
OPENAI_API_KEY |
OpenAI | Passive |
GEMINI_API_KEY |
Passive | |
OLLAMA_API_KEY |
Ollama | Probes local server |
| + ~15 more (Together, OpenRouter, Venice, etc.) | Various | Passive |
Common env vars like AWS_PROFILE, GH_TOKEN, and GEMINI_API_KEY are frequently set for unrelated tools.
Suggested Fix
- When
models.providersis empty/missing → auto-detect everything (current behavior, great for zero-config onboarding) - When
models.providershas entries → use exactly what is configured. Do not merge implicit providers. Do not fall back to env vars for auth on configured providers.
Workaround
Until fixed, users with explicit provider configs can either:
- Add
"bedrockDiscovery": { "enabled": false }undermodelsin config (suppresses Bedrock specifically) - Scope conflicting env vars so they do not leak into the gateway process (e.g., alias-scoped vars instead of global exports)
Environment
- OpenClaw: 2026.3.2
- OS: macOS 15.3.2 (arm64)
- Config: LiteLLM proxy with explicit
models.providerscontaininglitellm/bedrock-*model routing - Trigger:
AWS_PROFILEset globally for Claude Code Bedrock integration