Environment
- Dario: 3.4.1 (also reproduced on 3.4.0)
- Claude Code: 2.1.104
- Platform: Linux x64 (Ubuntu VPS)
- OpenClaw: 2026.4.9
- Device identity: detected
- OAuth: valid (token expires ~8h from testing)
Problem
Running OpenClaw agents through dario in default mode. Simple curl tests consistently get billing: five_hour. Actual OC agent requests always get billing: overage. We never got a single non-overage request from OC regardless of what we changed.
Complete Debugging Trail
Step 1: cache_control fingerprint hypothesis
Built a Bun strip proxy (:3455 → :3456) that recursively removed all cache_control fields from request body and stripped prompt-caching-* from anthropic-beta headers before forwarding to dario.
Result: still overage. Dario's template injection adds cache_control back in anyway. We were stripping what dario intentionally adds.
Step 2: SDK headers fingerprint hypothesis
Captured exact headers OC was sending to dario:
x-stainless-arch, x-stainless-helper-method, x-stainless-lang, x-stainless-os
x-stainless-package-version: 0.73.0, x-stainless-runtime-version: v22.22.2
anthropic-dangerous-direct-browser-access: true
user-agent: Anthropic/JS 0.73.0
Stripped all of these at the strip proxy before forwarding to dario.
Result: still overage.
Step 3: Verified final headers reaching Anthropic
After stripping at proxy level + dario template replay, headers forwarded to Anthropic were clean:
{
"accept": "application/json",
"anthropic-beta": "fine-grained-tool-streaming-2025-05-14",
"anthropic-version": "2023-06-01",
"content-type": "application/json",
"user-agent": "Mozilla/5.0"
}
No SDK fingerprints, no cache headers. Result: still overage.
Step 4: curl vs OC agent isolation test
Same proxy setup, same endpoint. Curl always got five_hour. OC always got overage.
Observable differences:
| Property |
curl test |
OC agent |
| Messages |
1 |
155+ |
| Body size |
~500 bytes |
~295KB |
| Tools |
0–10 |
10 |
| Streaming |
yes/no |
yes |
| Extended thinking |
yes/no |
yes |
| Conversation history |
none |
full multi-turn |
Step 5: Tool count reduction
OC normally sends all available tools (50+). We added a hard limit to restrict OC to exactly 10 tools per request — matching what a typical Claude Code session sends.
Result: still overage. Tool count is not the trigger.
Step 6: context-1m pattern (misleading correlation)
Observed this in dario logs:
#10 POST /v1/messages
#10 context-1m rejected (400) — retrying without it
#11 billing: five_hour ✅
#11 POST /v1/messages
#11 context-1m rejected (400) — retrying without it
#12 billing: five_hour ✅
#12 POST /v1/messages
#12 no rejection
#13 billing: overage ❌
Looked like context-1m was the trigger. Patched dario to remove context-1m-2025-08-07 from the default beta string entirely.
Result: still overage. The five_hour results on retry were coincidental — possibly a brief window of Max plan capacity, not caused by removing context-1m.
Step 7: --passthrough mode
Tried thin proxy mode — OAuth swap only, no CC template injection.
Result: 100% overage, worse than default mode. Confirmed template injection helps but isn't sufficient for our traffic.
Step 8: --cli mode
This worked. No overage entries whatsoever. But --cli was removed in 3.4.1.
Step 9: OAuth profile bypass (unrelated bug, discovered during debugging)
OC agents had stored anthropic:claude-cli OAuth profiles. OC uses stored OAuth profiles over models.json baseUrl, meaning requests bypassed dario entirely and hit Anthropic directly. Cleared all OAuth profiles from all agents to ensure routing through dario.
This was a real bug but not related to the overage issue.
Step 10: Version updates
Updated dario 3.4.0 → 3.4.1 and Claude Code 2.1.101 → 2.1.104. No change in billing behavior.
Step 11: credentials clientId issue (discovered at end)
After extended testing, dario's token refresh started failing:
Refresh attempt 1/3 failed: HTTP 400 — Client with id [uuid] not found
Claude Code credentials at /root/.claude/.credentials.json contain no clientId field in the claudeAiOauth object. Dario's refresh needs the clientId. Access token still valid for several hours but will expire without refresh working.
Summary: Why It Doesn't Work
After exhaustive testing we believe the issue is server-side session-level classification at Anthropic, not client-side headers or request fields.
Evidence:
- Curl requests through the exact same proxy → five_hour
- OC agent requests through the same proxy → overage
- Every client-side variable we could control made no difference
- The only thing curl and OC differ on is conversation length, token throughput, and multi-turn session behavior
Our theory: Anthropic's billing classifier looks at aggregate session behavior (token volume per session, request frequency, conversation depth) rather than per-request headers. A single-turn curl request looks like a human. A 155-message multi-turn agent session with continuous streaming looks like an automated workload — which is exactly what Extra Usage billing is designed to capture.
The --cli mode worked because it doesn't use the API at all — it shells to the Claude Code CLI binary, which is a completely different code path that Anthropic's API billing classifier never sees.
Workaround
Migrating to openclaw-claude-bridge (shinglokto/openclaw-claude-bridge) which shells directly to claude --print with persistent sessions — same approach as the old --cli mode but built properly with tool support, session memory, and a dashboard.
Environment
Problem
Running OpenClaw agents through dario in default mode. Simple curl tests consistently get
billing: five_hour. Actual OC agent requests always getbilling: overage. We never got a single non-overage request from OC regardless of what we changed.Complete Debugging Trail
Step 1: cache_control fingerprint hypothesis
Built a Bun strip proxy (:3455 → :3456) that recursively removed all
cache_controlfields from request body and strippedprompt-caching-*fromanthropic-betaheaders before forwarding to dario.Result: still overage. Dario's template injection adds
cache_controlback in anyway. We were stripping what dario intentionally adds.Step 2: SDK headers fingerprint hypothesis
Captured exact headers OC was sending to dario:
Stripped all of these at the strip proxy before forwarding to dario.
Result: still overage.
Step 3: Verified final headers reaching Anthropic
After stripping at proxy level + dario template replay, headers forwarded to Anthropic were clean:
{ "accept": "application/json", "anthropic-beta": "fine-grained-tool-streaming-2025-05-14", "anthropic-version": "2023-06-01", "content-type": "application/json", "user-agent": "Mozilla/5.0" }No SDK fingerprints, no cache headers. Result: still overage.
Step 4: curl vs OC agent isolation test
Same proxy setup, same endpoint. Curl always got
five_hour. OC always gotoverage.Observable differences:
Step 5: Tool count reduction
OC normally sends all available tools (50+). We added a hard limit to restrict OC to exactly 10 tools per request — matching what a typical Claude Code session sends.
Result: still overage. Tool count is not the trigger.
Step 6: context-1m pattern (misleading correlation)
Observed this in dario logs:
Looked like context-1m was the trigger. Patched dario to remove
context-1m-2025-08-07from the default beta string entirely.Result: still overage. The five_hour results on retry were coincidental — possibly a brief window of Max plan capacity, not caused by removing context-1m.
Step 7: --passthrough mode
Tried thin proxy mode — OAuth swap only, no CC template injection.
Result: 100% overage, worse than default mode. Confirmed template injection helps but isn't sufficient for our traffic.
Step 8: --cli mode
This worked. No overage entries whatsoever. But --cli was removed in 3.4.1.
Step 9: OAuth profile bypass (unrelated bug, discovered during debugging)
OC agents had stored
anthropic:claude-cliOAuth profiles. OC uses stored OAuth profiles overmodels.json baseUrl, meaning requests bypassed dario entirely and hit Anthropic directly. Cleared all OAuth profiles from all agents to ensure routing through dario.This was a real bug but not related to the overage issue.
Step 10: Version updates
Updated dario 3.4.0 → 3.4.1 and Claude Code 2.1.101 → 2.1.104. No change in billing behavior.
Step 11: credentials clientId issue (discovered at end)
After extended testing, dario's token refresh started failing:
Claude Code credentials at
/root/.claude/.credentials.jsoncontain noclientIdfield in theclaudeAiOauthobject. Dario's refresh needs the clientId. Access token still valid for several hours but will expire without refresh working.Summary: Why It Doesn't Work
After exhaustive testing we believe the issue is server-side session-level classification at Anthropic, not client-side headers or request fields.
Evidence:
Our theory: Anthropic's billing classifier looks at aggregate session behavior (token volume per session, request frequency, conversation depth) rather than per-request headers. A single-turn curl request looks like a human. A 155-message multi-turn agent session with continuous streaming looks like an automated workload — which is exactly what Extra Usage billing is designed to capture.
The
--climode worked because it doesn't use the API at all — it shells to the Claude Code CLI binary, which is a completely different code path that Anthropic's API billing classifier never sees.Workaround
Migrating to
openclaw-claude-bridge(shinglokto/openclaw-claude-bridge) which shells directly toclaude --printwith persistent sessions — same approach as the old--climode but built properly with tool support, session memory, and a dashboard.