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

  1. On 401, re-run `codex login` to refresh the OAuth access token
  2. Read the embedded body in the error message — it usually names the exact problem (invalid token, forbidden account)
  3. On 429, back off / reduce usage-polling frequency before retrying
  4. 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

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


AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06). Data as JSON: /api/errors/f4dcdebeb7edcb09. Report an issue: GitHub.