openclaw - 💡(How to fix) Fix [Bug]: Pi runtime silently uses orphaned credentials from per-agent auth-profiles.json after their declarations are removed from openclaw.json — billing/quota leak [1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#72255Fetched 2026-04-27 05:32:29
View on GitHub
Comments
0
Participants
1
Timeline
0
Reactions
0
Author
Participants

When a user removes an auth profile declaration from openclaw.json (e.g. an anthropic:claude-set-up-token entry), the corresponding credential blob is not removed from the per-agent agents/<id>/agent/auth-profiles.json store. With embeddedHarness.fallback: "pi" set, the embedded Pi runtime continues to find that orphan credential when resolving auth for matching provider:, and silently uses it for live model calls — billing/quota goes against the orphan credential without any user-visible signal.

This is closely related to #43945 (subagents missing per-agent credentials silently fall back to cloud) and #40363 (API key rotation leaves stale auth-profiles.json), but the specific failure mode here is the Pi fallback path picking up removed credentials. Worth filing as its own ticket because (a) the credential was actively removed, not stale, and (b) the symptom is an unexpected billing source rather than missing credentials.

Error Message

  • (b) Loud path: if the gateway is going to use a credential whose declaration was removed, log a high-visibility WARN at the moment of selection ([auth] using credential 'anthropic:claude-set-up-token' which is not declared in openclaw.json), so users have a chance to notice the silent billing change. error=LLM request rejected: "You're out of extra usage. Add more at claude.ai/settings/usage and keep going."

Root Cause

This is closely related to #43945 (subagents missing per-agent credentials silently fall back to cloud) and #40363 (API key rotation leaves stale auth-profiles.json), but the specific failure mode here is the Pi fallback path picking up removed credentials. Worth filing as its own ticket because (a) the credential was actively removed, not stale, and (b) the symptom is an unexpected billing source rather than missing credentials.

Fix Action

Workaround

After removing a profile from openclaw.json auth.profiles, also delete the matching key from every agents/<id>/agent/auth-profiles.json:

python3 -c '
import json, os
ORPHANS = {"anthropic:claude-set-up-token"}  # whatever was removed
for f in [
    os.path.expanduser("~/.openclaw/agents/main/agent/auth-profiles.json"),
    os.path.expanduser("~/.openclaw/agents/kristen/agent/auth-profiles.json"),
    # ...other agents...
]:
    d = json.load(open(f))
    for k in ORPHANS:
        d.get("profiles", {}).pop(k, None)
    json.dump(d, open(f, "w"), indent=2)
'

Restart gateway. Confirm via a test message + checking the next [agent/embedded] or [agent/cli-backend] log line for the expected provider=.

Code Example

[agent/embedded] embedded run agent end: ... provider=anthropic
  error=LLM request rejected: "You're out of extra usage. Add more at claude.ai/settings/usage and keep going."
  rawError=400 invalid_request_error
[agent/embedded] auth profile failure state updated: profile=sha256:<hash> provider=anthropic reason=billing

---

python3 -c '
import json, os
ORPHANS = {"anthropic:claude-set-up-token"}  # whatever was removed
for f in [
    os.path.expanduser("~/.openclaw/agents/main/agent/auth-profiles.json"),
    os.path.expanduser("~/.openclaw/agents/kristen/agent/auth-profiles.json"),
    # ...other agents...
]:
    d = json.load(open(f))
    for k in ORPHANS:
        d.get("profiles", {}).pop(k, None)
    json.dump(d, open(f, "w"), indent=2)
'
RAW_BUFFERClick to expand / collapse

[Bug]: Pi runtime silently uses orphaned credentials from per-agent auth-profiles.json after their declarations are removed from openclaw.json — billing/quota leak

Bug type

Bug — silent credential reuse / unexpected provider routing

Beta release blocker

No (but security/billing-relevant)

Summary

When a user removes an auth profile declaration from openclaw.json (e.g. an anthropic:claude-set-up-token entry), the corresponding credential blob is not removed from the per-agent agents/<id>/agent/auth-profiles.json store. With embeddedHarness.fallback: "pi" set, the embedded Pi runtime continues to find that orphan credential when resolving auth for matching provider:, and silently uses it for live model calls — billing/quota goes against the orphan credential without any user-visible signal.

This is closely related to #43945 (subagents missing per-agent credentials silently fall back to cloud) and #40363 (API key rotation leaves stale auth-profiles.json), but the specific failure mode here is the Pi fallback path picking up removed credentials. Worth filing as its own ticket because (a) the credential was actively removed, not stale, and (b) the symptom is an unexpected billing source rather than missing credentials.

Reproduction

Setting: openclaw 2026.4.24 on Linux. Anthropic Claude CLI configured (~/.claude/.credentials.json populated via claude login, Pro/Max plan). Goal: daily-drive claude-cli/<model> with openai-codex/* as fallback.

  1. Begin with auth.profiles containing both:

    • anthropic:claude-cli (provider=claude-cli, mode=oauth) — used for daily-drive
    • anthropic:claude-set-up-token (provider=anthropic, mode=token) — a long-lived sk-ant-oat01-… OAT created earlier via claude setup-token
  2. Decide to consolidate: remove anthropic:claude-set-up-token from openclaw.json auth.profiles. Note: this leaves the credential blob in agents/<id>/agent/auth-profiles.json. Restart gateway.

  3. Configure default fallback chain to use canonical anthropic/<model> IDs (e.g. via openclaw configure choosing "Anthropic Claude CLI"). Set embeddedHarness.runtime: "auto" and embeddedHarness.fallback: "pi".

  4. Send a request that the canonical anthropic/claude-sonnet-4-6 would normally route through claude-cli/... (via display canonicalization). Because no anthropic-provider auth profile is declared in openclaw.json (only the legacy anthropic:claude-cli with provider: claude-cli), the harness lookup for the canonical form falls through to Pi.

  5. Pi's auth resolver finds the orphan anthropic:claude-set-up-token credential in the per-agent auth-profiles.json store and uses it. No [agent/cli-backend] line is emitted; the request goes through provider=anthropic direct API.

Expected behavior

Either:

  • (a) Strict path: Pi should only use credentials whose profile is declared in openclaw.json auth.profiles. Removing a declaration should immediately stop the credential being used at runtime, regardless of whether the blob is still on disk.
  • (b) Loud path: if the gateway is going to use a credential whose declaration was removed, log a high-visibility WARN at the moment of selection ([auth] using credential 'anthropic:claude-set-up-token' which is not declared in openclaw.json), so users have a chance to notice the silent billing change.

A openclaw doctor or openclaw auth list warning for "credential present in auth-profiles.json but not declared in openclaw.json" would also help users find this state proactively.

Actual behavior

The orphan credential is silently used. The only signal is when the credential's quota is exhausted, at which point the gateway logs:

[agent/embedded] embedded run agent end: ... provider=anthropic
  error=LLM request rejected: "You're out of extra usage. Add more at claude.ai/settings/usage and keep going."
  rawError=400 invalid_request_error
[agent/embedded] auth profile failure state updated: profile=sha256:<hash> provider=anthropic reason=billing

By the time this fires, the user has already been billed against the wrong account for the runtime period since profile removal.

Why it's not just "stale credentials" (#40363)

  • #40363 is about rotation leaving an old key in auth-profiles.json. Here the user explicitly removed the entry from openclaw.json. They expected the credential to no longer be in use.
  • #43945 is about missing credentials causing an unexpected cloud fallback. Here the credential is present, the cloud fallback works, but it's billing against an account the user thought they'd retired.
  • Common thread: the per-agent auth-profiles.json is the canonical credential store, but openclaw.json auth.profiles is what users edit and reason about. A drift between the two creates ghost credentials.

Suggested fix directions

  1. Treat openclaw.json auth.profiles as authoritative. On gateway boot, prune auth-profiles.json entries whose profile id is not declared in openclaw.json. Move the removed blobs into auth-profiles.json.orphans for recovery, with a single startup log line listing them.
  2. Or add an explicit declared-profile-id allowlist to the auth resolver, ignoring blobs not in the list at lookup time.
  3. Or at minimum, surface this in openclaw doctor with a clear warning + remediation command.

Environment

  • OpenClaw 2026.4.24 (cbcfdf6) — observed locally. The failure mode appears to be in the resolver layer and may affect adjacent versions, but only confirmed on 2026.4.24.
  • Linux x86_64 (Ubuntu 24)
  • Node 22
  • Install method: npm -g
  • Claude CLI 2.1.119 (Pro plan)

Files involved

  • auth.profiles in ~/.openclaw/openclaw.json
  • agents/<id>/agent/auth-profiles.json (per-agent credential store; main, kristen, codex, llm in our case)
  • dist/extensions/anthropic/register.runtime.jsresolveClaudeCliSyntheticAuth and the auth profile resolver paths
  • dist/pi-embedded-*.js — Pi runtime auth lookup

Workaround

After removing a profile from openclaw.json auth.profiles, also delete the matching key from every agents/<id>/agent/auth-profiles.json:

python3 -c '
import json, os
ORPHANS = {"anthropic:claude-set-up-token"}  # whatever was removed
for f in [
    os.path.expanduser("~/.openclaw/agents/main/agent/auth-profiles.json"),
    os.path.expanduser("~/.openclaw/agents/kristen/agent/auth-profiles.json"),
    # ...other agents...
]:
    d = json.load(open(f))
    for k in ORPHANS:
        d.get("profiles", {}).pop(k, None)
    json.dump(d, open(f, "w"), indent=2)
'

Restart gateway. Confirm via a test message + checking the next [agent/embedded] or [agent/cli-backend] log line for the expected provider=.

extent analysis

TL;DR

To fix the issue, treat openclaw.json auth.profiles as authoritative and prune auth-profiles.json entries whose profile id is not declared in openclaw.json on gateway boot.

Guidance

  • Identify the removed profile id (e.g., anthropic:claude-set-up-token) and manually delete the matching key from every agents/<id>/agent/auth-profiles.json file.
  • Restart the gateway to ensure the changes take effect.
  • Verify the fix by sending a test request and checking the next [agent/embedded] or [agent/cli-backend] log line for the expected provider=.
  • Consider implementing a startup log line to list removed blobs and moving them into auth-profiles.json.orphans for recovery.

Example

The provided Python script can be used to automate the deletion of orphaned credentials:

python3 -c '
import json, os
ORPHANS = {"anthropic:claude-set-up-token"}  # whatever was removed
for f in [
    os.path.expanduser("~/.openclaw/agents/main/agent/auth-profiles.json"),
    os.path.expanduser("~/.openclaw/agents/kristen/agent/auth-profiles.json"),
    # ...other agents...
]:
    d = json.load(open(f))
    for k in ORPHANS:
        d.get("profiles", {}).pop(k, None)
    json.dump(d, open(f, "w"), indent=2)
'

Notes

This fix assumes that the issue is specific to the Pi runtime and the embeddedHarness.fallback: "pi" configuration. The provided workaround may need to be adapted for other configurations or versions.

Recommendation

Apply the workaround by manually deleting the orphaned credentials and restarting the gateway, as this is a more immediate solution to prevent silent billing/quota leaks.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

FAQ

Expected behavior

Either:

  • (a) Strict path: Pi should only use credentials whose profile is declared in openclaw.json auth.profiles. Removing a declaration should immediately stop the credential being used at runtime, regardless of whether the blob is still on disk.
  • (b) Loud path: if the gateway is going to use a credential whose declaration was removed, log a high-visibility WARN at the moment of selection ([auth] using credential 'anthropic:claude-set-up-token' which is not declared in openclaw.json), so users have a chance to notice the silent billing change.

A openclaw doctor or openclaw auth list warning for "credential present in auth-profiles.json but not declared in openclaw.json" would also help users find this state proactively.

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - 💡(How to fix) Fix [Bug]: Pi runtime silently uses orphaned credentials from per-agent auth-profiles.json after their declarations are removed from openclaw.json — billing/quota leak [1 participants]