chenhg5/cc-connect · error
usage endpoint returned status %d: %s
Error message
usage endpoint returned status %d: %s
What it means
fetchUsage expects the usage endpoint to return HTTP 200. Any other status (401 expired token, 403 wrong account id, 429 rate limit, 5xx) produces this error, which embeds the status code and up to 512 bytes of the response body for diagnosis. The library does not retry non-200 responses; it fails with the server's own diagnostic payload.
Source
Thrown at agent/codex/usage.go:110
func (a *Agent) fetchUsage(ctx context.Context, client *http.Client, tokens codexOAuthTokens) (*core.UsageReport, error) {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, codexUsageURL, nil)
if err != nil {
return nil, err
}
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,
}View on GitHub (pinned to 4000b2338a)
Solutions
- On 401, re-run `codex login` to refresh the OAuth access token
- Read the embedded body in the error message — it usually names the exact problem (invalid token, forbidden account)
- On 429, back off / reduce usage-polling frequency before retrying
- On 5xx, wait and retry; check ChatGPT/OpenAI status pages for incidents
Example fix
// before: retries blindly on any failure
usage, err := agent.GetUsage(ctx)
if err != nil { time.Sleep(time.Second); retry() }
// after: branch on status encoded in the error
usage, err := agent.GetUsage(ctx)
if err != nil && strings.Contains(err.Error(), "status 401") {
exec.Command("codex", "login").Run() // refresh token
} Defensive patterns
Strategy: try-catch
Try / catch
_, err := agent.GetUsage(ctx)
if err != nil {
var status int
if _, scan := fmt.Sscanf(err.Error(), "usage endpoint returned status %d", &status); scan == nil {
switch {
case status == 401: refreshCodexLogin()
case status == 429: backoffAndRetry()
case status >= 500: scheduleRetry()
}
}
} Prevention
- Refresh `codex login` tokens before they expire
- Respect rate limits; don't poll usage endpoints aggressively
- Read the embedded response body in the error before deciding
- Track backend status pages for 5xx windows
When it happens
Trigger: resp.StatusCode != http.StatusOK in fetchUsage after a successful request — e.g. access token expired (401), account_id header mismatch (403), server-side throttling (429), or backend outage (500/503). Exercised by TestFetchUsage_HTTPError.
Common situations: Long-lived auth.json whose access token expired and needs `codex login` refresh; account_id not matching the token's account; heavy polling triggering 429; transient ChatGPT backend incidents.
Understand the failure class
Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.
Related errors
- request usage endpoint: %w
- decode usage response: %w
- minimax tts API %d: %s
- first-chunk: unexpected status %d
- read %s: %w
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/f4dcdebeb7edcb09.
Report an issue: GitHub.