Summary
Since 2026-06-16 ~18:05 UTC, every Anthropic quota poll fails to decode. The Anthropic agent goes healthy=0 and quota tracking stops. Auth is fine — the OAuth token refreshes normally; this is purely a response-schema decode failure.
Error (every poll, ~10 min interval, continuous)
level=ERROR msg="Failed to fetch Anthropic quotas" \
error="anthropic: invalid response: json: cannot unmarshal array into Go value of type api.AnthropicQuotaEntry"
A daemon restart does not help — it re-fails on the first poll after boot.
Versions affected
- Reproduced on v2.12.0.
- Type is unchanged through v2.12.5 (latest) and
main → all current versions are affected. (v2.12.1–v2.12.5 changelogs touch Codex/Antigravity/self-update, nothing on the Anthropic quota schema.)
Root cause
AnthropicClient.FetchQuotas (internal/api/anthropic_client.go) GETs https://api.anthropic.com/api/oauth/usage and decodes into:
// internal/api/anthropic_types.go:21
type AnthropicQuotaResponse map[string]*AnthropicQuotaEntry
// internal/api/anthropic_client.go (~line 156)
var quotaResp AnthropicQuotaResponse
if err := json.Unmarshal(body, "aResp); err != nil { ... } // <-- fails here
The error is cannot unmarshal array into AnthropicQuotaEntry (not into map), so the top-level object is intact, but at least one bucket value, which the code expects to be a single AnthropicQuotaEntry object, is now a JSON array (Anthropic appears to have split a window into per-model entries, e.g. seven_day → [ {…}, {…} ]). Because the whole map is unmarshalled in one pass, a single array-valued key fails the entire decode → all quota data is lost, not just the affected bucket.
Request used (for repro)
GET https://api.anthropic.com/api/oauth/usage
Authorization: Bearer <oauth-access-token>
Content-Type: application/json
anthropic-beta: oauth-2025-04-20
User-Agent: claude-code/2.1.69
Inspect the response: one of the top-level keys now holds [ … ] instead of { … }.
Impact
Anthropic quota tracking is fully down for OAuth/subscription users since the API change. Anything gating on onwatch_agent_healthy / quota metrics fails closed.
Suggested fix
Make the per-bucket value tolerate both shapes. Minimal approach — a wrapper type with a custom UnmarshalJSON that accepts a single object or an array of AnthropicQuotaEntry:
type quotaBucket []*AnthropicQuotaEntry // always a slice internally
func (b *quotaBucket) UnmarshalJSON(data []byte) error {
trimmed := bytes.TrimSpace(data)
if len(trimmed) > 0 && trimmed[0] == '[' {
var arr []*AnthropicQuotaEntry
if err := json.Unmarshal(data, &arr); err != nil { return err }
*b = arr
return nil
}
var one AnthropicQuotaEntry
if err := json.Unmarshal(data, &one); err != nil { return err }
*b = []*AnthropicQuotaEntry{&one}
return nil
}
// type AnthropicQuotaResponse map[string]quotaBucket
Then decide downstream semantics for multi-entry buckets (e.g. expand into per-model keys like seven_day_opus / seven_day_sonnet, or aggregate by max utilization). Happy to PR if useful.
Summary
Since 2026-06-16 ~18:05 UTC, every Anthropic quota poll fails to decode. The Anthropic agent goes
healthy=0and quota tracking stops. Auth is fine — the OAuth token refreshes normally; this is purely a response-schema decode failure.Error (every poll, ~10 min interval, continuous)
A daemon restart does not help — it re-fails on the first poll after boot.
Versions affected
main→ all current versions are affected. (v2.12.1–v2.12.5 changelogs touch Codex/Antigravity/self-update, nothing on the Anthropic quota schema.)Root cause
AnthropicClient.FetchQuotas(internal/api/anthropic_client.go) GETshttps://api.anthropic.com/api/oauth/usageand decodes into:The error is
cannot unmarshal array into AnthropicQuotaEntry(notinto map), so the top-level object is intact, but at least one bucket value, which the code expects to be a singleAnthropicQuotaEntryobject, is now a JSON array (Anthropic appears to have split a window into per-model entries, e.g.seven_day→[ {…}, {…} ]). Because the whole map is unmarshalled in one pass, a single array-valued key fails the entire decode → all quota data is lost, not just the affected bucket.Request used (for repro)
Inspect the response: one of the top-level keys now holds
[ … ]instead of{ … }.Impact
Anthropic quota tracking is fully down for OAuth/subscription users since the API change. Anything gating on
onwatch_agent_healthy/ quota metrics fails closed.Suggested fix
Make the per-bucket value tolerate both shapes. Minimal approach — a wrapper type with a custom
UnmarshalJSONthat accepts a single object or an array ofAnthropicQuotaEntry:Then decide downstream semantics for multi-entry buckets (e.g. expand into per-model keys like
seven_day_opus/seven_day_sonnet, or aggregate by max utilization). Happy to PR if useful.