Summary
When using Ollama providers (e.g. ollama-remote for a remote Ollama instance), the configured apiKey value (typically "ollama-local") is classified as a marker (non-secret placeholder) by the auth pipeline. As a result, it is not written to the agent-level auth-profiles.json.
The main session works correctly because it reads apiKey directly from openclaw.json. However, subagents rely exclusively on auth-profiles.json for credential lookup — and find no entry for the Ollama provider. This causes a 401 auth error, triggering a silent fallback to the next model in the fallback chain (typically a cloud model like openai/gpt-4.1-mini).
The user receives a valid response and has no indication that their prompt was routed to a cloud provider instead of the intended local model.
Security & Privacy Impact
This is a privacy regression with real-world consequences:
- Users choose local Ollama models specifically for data sovereignty — sensitive prompts, proprietary code, medical data, or personal information should never leave the local network.
- The silent fallback bypasses user intent and privacy guarantees without any warning, notification, or log entry visible to the end user.
- Subagent tasks may contain context from the main session (file contents, user data, conversation history) that the user explicitly intended to keep local.
- The fallback is invisible in normal usage — only deep gateway log analysis (
model-fallback/decision entries in /tmp/openclaw/openclaw-*.log) reveals what happened.
- Risk of targeted exploitation: A malicious actor with knowledge of this behavior could craft scenarios that trigger auth failures on local providers, forcing sensitive data to route through cloud APIs.
This means: a user who believes their data stays local may unknowingly send it to OpenAI, Google, or other cloud providers.
Steps to Reproduce
- Configure an Ollama remote provider in
openclaw.json:
{
"models": {
"providers": {
"ollama-remote": {
"baseUrl": "http://192.168.178.122:11434",
"apiKey": "ollama-local",
"api": "ollama",
"models": [{ "id": "qwen3.5:27b", "name": "Qwen 3.5 27B" }]
}
}
},
"agents": {
"defaults": {
"models": { "ollama-remote/qwen3.5:27b": {} },
"model": { "fallbacks": ["openai/gpt-4.1-mini"] }
}
}
}
- Restart the gateway
- Check
auth-profiles.json:
cat ~/.openclaw/agents/main/agent/auth-profiles.json | jq '.profiles | keys'
# → ["anthropic:default", "xai:default"] — no ollama-remote entry
- Run
openclaw models status:
ollama-remote effective=missing:missing | models.json=marker(ollama-local)
- Spawn a subagent targeting the Ollama model
- Observed: Subagent completes in ~3-4 seconds, claims to be "GPT-4.1-mini"
- Expected: Subagent uses the local Ollama model (slower, ~30s+), or fails with a clear error if the local model is unavailable
Root Cause Analysis
Affected components: Gateway auth pipeline (auth-profiles writer/sync), subagent credential resolver, model fallback engine.
The auth pipeline has a marker detection mechanism that classifies certain API key values (like "ollama-local", "OPENAI_API_KEY", etc.) as non-secret placeholders. These markers are intentionally excluded from auth-profiles.json to prevent example/dummy keys from polluting the secret store.
However, for Ollama providers, the "marker" value IS the intended credential — Ollama doesn't require real authentication. The marker filter doesn't distinguish between "placeholder that should be replaced" and "intentionally simple key for an auth-free service."
The credential resolution chain for subagents:
Read from openclaw.json directly (not available to subagents)
- Look up in
auth-profiles.json → empty for Ollama → 401
- Check environment variables → not propagated to subagent lanes
- Fallback to next model (cloud) → silent success
Additionally, the gateway regenerates auth-profiles.json on every restart, overwriting any manual fixes.
Log Evidence
[ERROR] FailoverError: No API key found for provider "ollama-remote".
Auth store: ~/.openclaw/agents/main/agent/auth-profiles.json
[WARN] model_fallback_decision: candidate_failed
requestedProvider: ollama-remote
requestedModel: qwen3.5:27b
reason: auth, status: 401
nextCandidate: openai/gpt-4.1-mini
[WARN] model_fallback_decision: candidate_succeeded
candidateProvider: openai
candidateModel: gpt-4.1-mini
previousAttempts: [{provider: ollama-remote, reason: auth, status: 401}]
Note: These entries are only visible in the gateway file log (/tmp/openclaw/openclaw-*.log), not in any user-facing UI or dashboard. Users have no way to detect this behavior without manually inspecting logs.
Proposed Fixes (ordered by priority)
Fix 1: Propagate all provider apiKeys to auth-profiles.json (minimal, quick win)
Write all models.providers.*.apiKey values to auth-profiles.json, regardless of marker classification. The auth store should reflect the config, not second-guess it. If a user configured a key, it should be available to all sessions including subagents.
Affected: Gateway auth-profiles writer/sync logic.
Fix 2: Skip auth lookup for auth-free providers (architectural)
Introduce an auth: "none" provider capability. When api: "ollama" is set (or explicitly configured), the auth pipeline should be bypassed entirely — no auth-profiles lookup needed. Ollama doesn't use authentication; the current system forces users to provide a dummy key just to satisfy the pipeline.
This would also benefit other local/auth-free providers like LM Studio, vLLM, llama.cpp server, and similar local inference backends.
Affected: Provider auth resolver, auth pipeline.
Fix 3: Add a fail-closed policy flag for local-only routing (privacy)
Add a per-agent or per-provider policy flag like allowCloudFallback: false or requireLocal: true. When set, the fallback mechanism must never cross the local→cloud boundary silently. If the local model fails, the task should fail with a clear error rather than leak data to a cloud provider.
Consider how this interacts with existing fallback chains — the flag should override automatic fallback behavior when privacy is at stake.
Affected: Model fallback engine, agent config schema.
Fix 4: Surface fallback decisions to the user (transparency)
When a model fallback crosses a provider boundary (especially local→cloud), emit a user-visible warning — not just a log entry buried in /tmp. The user should always know when their intended model was substituted. This could be a notification in the chat, a dashboard alert, or at minimum a clearly visible log line.
Affected: Model fallback engine, notification/messaging system.
Fix 5: Add CI/integration tests for auth-profiles behavior (prevention)
Establish automated tests that verify auth-profiles.json is correctly populated for all provider types — especially local providers with marker-style keys. This prevents regressions in the auth subsystem when future changes are made.
Affected: Test suite, CI pipeline.
Workaround
- Manually add Ollama entries to
auth-profiles.json:
{
"ollama-remote:default": {
"type": "api_key",
"provider": "ollama-remote",
"key": "sk-ollama-dummy"
}
}
- ⚠️ Protect the file from being overwritten on restart:
chmod 444 ~/.openclaw/agents/main/agent/auth-profiles.json
⚠️ Important caveats:
- The key value must NOT be
"ollama-local" — it gets re-classified as a marker. Use any non-marker string like "sk-ollama-dummy".
- The
chmod 444 prevents the gateway from updating auth-profiles.json for ANY provider — adding or rotating keys for other providers (Anthropic, OpenAI, etc.) will silently fail until the file is made writable again.
- After
openclaw update, verify the file still contains the Ollama entries — updates may regenerate the file.
- This is a dirty hack, not a sustainable solution.
Related Issue
Ollama model cold-start causes timeout fallback (see #43946)
Even with auth fixed, Ollama models need ~13 seconds to load on first request. The default LLM request timeout appears too short for cold-start scenarios, causing a secondary timeout-based fallback (status 408). Pre-loading models via curl /api/generate with keep_alive works around this, but a configurable requestTimeout per provider or model would be the proper fix.
Environment
- OpenClaw 2026.3.11
- Ollama 0.17.7 (remote, Windows + local, Linux)
- Both
ollama-local and ollama-remote providers affected
- Issue likely affects all Ollama provider configurations used in subagent context
Summary
When using Ollama providers (e.g.
ollama-remotefor a remote Ollama instance), the configuredapiKeyvalue (typically"ollama-local") is classified as a marker (non-secret placeholder) by the auth pipeline. As a result, it is not written to the agent-levelauth-profiles.json.The main session works correctly because it reads
apiKeydirectly fromopenclaw.json. However, subagents rely exclusively onauth-profiles.jsonfor credential lookup — and find no entry for the Ollama provider. This causes a401 autherror, triggering a silent fallback to the next model in the fallback chain (typically a cloud model likeopenai/gpt-4.1-mini).The user receives a valid response and has no indication that their prompt was routed to a cloud provider instead of the intended local model.
Security & Privacy Impact
This is a privacy regression with real-world consequences:
model-fallback/decisionentries in/tmp/openclaw/openclaw-*.log) reveals what happened.This means: a user who believes their data stays local may unknowingly send it to OpenAI, Google, or other cloud providers.
Steps to Reproduce
openclaw.json:{ "models": { "providers": { "ollama-remote": { "baseUrl": "http://192.168.178.122:11434", "apiKey": "ollama-local", "api": "ollama", "models": [{ "id": "qwen3.5:27b", "name": "Qwen 3.5 27B" }] } } }, "agents": { "defaults": { "models": { "ollama-remote/qwen3.5:27b": {} }, "model": { "fallbacks": ["openai/gpt-4.1-mini"] } } } }auth-profiles.json:openclaw models status:Root Cause Analysis
Affected components: Gateway auth pipeline (auth-profiles writer/sync), subagent credential resolver, model fallback engine.
The auth pipeline has a marker detection mechanism that classifies certain API key values (like
"ollama-local","OPENAI_API_KEY", etc.) as non-secret placeholders. These markers are intentionally excluded fromauth-profiles.jsonto prevent example/dummy keys from polluting the secret store.However, for Ollama providers, the "marker" value IS the intended credential — Ollama doesn't require real authentication. The marker filter doesn't distinguish between "placeholder that should be replaced" and "intentionally simple key for an auth-free service."
The credential resolution chain for subagents:
Read from(not available to subagents)openclaw.jsondirectlyauth-profiles.json→ empty for Ollama → 401Additionally, the gateway regenerates
auth-profiles.jsonon every restart, overwriting any manual fixes.Log Evidence
Note: These entries are only visible in the gateway file log (
/tmp/openclaw/openclaw-*.log), not in any user-facing UI or dashboard. Users have no way to detect this behavior without manually inspecting logs.Proposed Fixes (ordered by priority)
Fix 1: Propagate all provider apiKeys to auth-profiles.json (minimal, quick win)
Write all
models.providers.*.apiKeyvalues toauth-profiles.json, regardless of marker classification. The auth store should reflect the config, not second-guess it. If a user configured a key, it should be available to all sessions including subagents.Affected: Gateway auth-profiles writer/sync logic.
Fix 2: Skip auth lookup for auth-free providers (architectural)
Introduce an
auth: "none"provider capability. Whenapi: "ollama"is set (or explicitly configured), the auth pipeline should be bypassed entirely — no auth-profiles lookup needed. Ollama doesn't use authentication; the current system forces users to provide a dummy key just to satisfy the pipeline.This would also benefit other local/auth-free providers like LM Studio, vLLM, llama.cpp server, and similar local inference backends.
Affected: Provider auth resolver, auth pipeline.
Fix 3: Add a fail-closed policy flag for local-only routing (privacy)
Add a per-agent or per-provider policy flag like
allowCloudFallback: falseorrequireLocal: true. When set, the fallback mechanism must never cross the local→cloud boundary silently. If the local model fails, the task should fail with a clear error rather than leak data to a cloud provider.Consider how this interacts with existing fallback chains — the flag should override automatic fallback behavior when privacy is at stake.
Affected: Model fallback engine, agent config schema.
Fix 4: Surface fallback decisions to the user (transparency)
When a model fallback crosses a provider boundary (especially local→cloud), emit a user-visible warning — not just a log entry buried in
/tmp. The user should always know when their intended model was substituted. This could be a notification in the chat, a dashboard alert, or at minimum a clearly visible log line.Affected: Model fallback engine, notification/messaging system.
Fix 5: Add CI/integration tests for auth-profiles behavior (prevention)
Establish automated tests that verify
auth-profiles.jsonis correctly populated for all provider types — especially local providers with marker-style keys. This prevents regressions in the auth subsystem when future changes are made.Affected: Test suite, CI pipeline.
Workaround
auth-profiles.json:{ "ollama-remote:default": { "type": "api_key", "provider": "ollama-remote", "key": "sk-ollama-dummy" } }chmod 444 ~/.openclaw/agents/main/agent/auth-profiles.json"ollama-local"— it gets re-classified as a marker. Use any non-marker string like"sk-ollama-dummy".chmod 444prevents the gateway from updatingauth-profiles.jsonfor ANY provider — adding or rotating keys for other providers (Anthropic, OpenAI, etc.) will silently fail until the file is made writable again.openclaw update, verify the file still contains the Ollama entries — updates may regenerate the file.Related Issue
Ollama model cold-start causes timeout fallback (see #43946)
Even with auth fixed, Ollama models need ~13 seconds to load on first request. The default LLM request timeout appears too short for cold-start scenarios, causing a secondary timeout-based fallback (status 408). Pre-loading models via
curl /api/generatewithkeep_aliveworks around this, but a configurablerequestTimeoutper provider or model would be the proper fix.Environment
ollama-localandollama-remoteproviders affected