chenhg5/cc-connect · error
decode usage response: %w
Error message
decode usage response: %w
What it means
After a 200 response, fetchUsage decodes the JSON body into codexUsageResponse. This error wraps the json.Decoder failure when the body is not the expected usage JSON — an HTML error page, an empty body, or a schema change in the backend response. It indicates the server answered 200 but with unusable content.
Source
Thrown at agent/codex/usage.go:115
}
req.Header.Set("Authorization", "Bearer "+tokens.AccessToken)
req.Header.Set("ChatGPT-Account-Id", tokens.AccountID)
req.Header.Set("User-Agent", "codex-cli")
resp, err := client.Do(req)
if err != nil {
return nil, fmt.Errorf("request usage endpoint: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(io.LimitReader(resp.Body, 512))
return nil, fmt.Errorf("usage endpoint returned status %d: %s", resp.StatusCode, strings.TrimSpace(string(body)))
}
var payload codexUsageResponse
if err := json.NewDecoder(resp.Body).Decode(&payload); err != nil {
return nil, fmt.Errorf("decode usage response: %w", err)
}
return mapCodexUsage(payload), nil
}
func mapCodexUsage(payload codexUsageResponse) *core.UsageReport {
report := &core.UsageReport{
Provider: "codex",
AccountID: payload.AccountID,
UserID: payload.UserID,
Email: payload.Email,
Plan: payload.PlanType,
}
if payload.RateLimit != nil {
report.Buckets = append(report.Buckets, core.UsageBucket{
Name: "Rate limit",
Allowed: payload.RateLimit.Allowed,View on GitHub (pinned to 4000b2338a)
Solutions
- Log/capture the raw response body to see what the 200 actually contained
- Check whether an auth/proxy layer is intercepting the request (captive portal, SSO redirect)
- Pin/upgrade cc-connect to a version matching the current Codex usage endpoint schema
- Retry later if it's a transient backend anomaly; verify with a manual curl of the endpoint
Example fix
// before
usage, err := agent.GetUsage(ctx)
// after: detect a non-JSON 200 body early
if resp, _ := http.Get(usageURL); resp != nil {
var probe any
if err := json.NewDecoder(resp.Body).Decode(&probe); err != nil {
log.Fatalf("usage endpoint returned non-JSON 200 body — check proxy/captive portal")
}
}
usage, err := agent.GetUsage(ctx) Defensive patterns
Strategy: try-catch
Try / catch
_, err := agent.GetUsage(ctx)
if err != nil && strings.Contains(err.Error(), "decode usage response") {
// 200 with non-JSON body: capture raw body and surface it
log.Printf("unexpected usage payload; check proxy/captive portal; raw: %s", lastRawBody)
} Prevention
- Bypass or correctly authenticate corporate proxies
- Log raw response bodies on decode failure for diagnosis
- Pin cc-connect/Codex versions known to match the endpoint schema
- Add a schema smoke-test after upgrading either component
When it happens
Trigger: json.NewDecoder(resp.Body).Decode(&payload) fails in fetchUsage after a 200 response: proxy captive portal returns HTML with 200, CDN/auth layer returns empty body, or the usage endpoint schema changed. Callers: GetUsage.
Common situations: Corporate proxies/captive portals returning 200 HTML login pages; auth edge cases where a 200 carries an error object instead of usage data; OpenAI changing the usage endpoint response shape after an API update.
Related errors
- parse auth.json: %w
- request usage endpoint: %w
- usage endpoint returned status %d: %s
- parse JSON from %s: %w
- parse existing Agy hooks %s: %w
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/4de0e03161d91fca.
Report an issue: GitHub.