{"record":{"id":"bcb821fc1055b8f9","repo":"sipeed/picoclaw","slug":"reading-usage-response-w","errorCode":null,"errorMessage":"reading usage response: %w","messagePattern":"reading usage response: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/auth/anthropic_usage.go","lineNumber":45,"sourceCode":"func FetchAnthropicUsage(token string) (*AnthropicUsage, error) {\n\treq, err := http.NewRequest(\"GET\", anthropicUsageURL, nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treq.Header.Set(\"Authorization\", \"Bearer \"+token)\n\treq.Header.Set(\"Anthropic-Version\", anthropicAPIVersion)\n\treq.Header.Set(\"Anthropic-Beta\", anthropicBetaHeader)\n\n\tclient := &http.Client{Timeout: 10 * time.Second}\n\tresp, err := client.Do(req)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\tdefer resp.Body.Close()\n\n\tbody, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"reading usage response: %w\", err)\n\t}\n\n\tif resp.StatusCode != http.StatusOK {\n\t\tif resp.StatusCode == http.StatusForbidden {\n\t\t\treturn nil, fmt.Errorf(\"insufficient scope: usage endpoint requires oauth scope\")\n\t\t}\n\t\treturn nil, fmt.Errorf(\"usage request failed (%d): %s\", resp.StatusCode, string(body))\n\t}\n\n\tvar result struct {\n\t\tFiveHour struct {\n\t\t\tUtilization float64 `json:\"utilization\"`\n\t\t} `json:\"five_hour\"`\n\t\tSevenDay struct {\n\t\t\tUtilization float64 `json:\"utilization\"`\n\t\t} `json:\"seven_day\"`\n\t}\n\tif err := json.Unmarshal(body, &result); err != nil {","sourceCodeStart":27,"sourceCodeEnd":63,"githubUrl":"https://github.com/sipeed/picoclaw/blob/49183d7e8daed0dba89ddbb6fcb60089401d9680/pkg/auth/anthropic_usage.go#L27-L63","documentation":"io.ReadAll(resp.Body) failed at pkg/auth/anthropic_usage.go:45 while reading the Anthropic usage endpoint's response body. The HTTP request itself succeeded (client.Do returned), so this is a mid-body transport failure — the connection broke or the 10-second http.Client timeout fired while streaming the body. Status code handling never runs in this case.","triggerScenarios":"Connection reset between headers and body completion; slow endpoint where the fixed 10s client timeout (client := &http.Client{Timeout: 10 * time.Second}) fires during body read; intermediary proxy truncating the response; TLS renegotiation dropping the stream.","commonSituations":"Mobile/high-latency networks; corporate proxies that buffer headers then cut long bodies; Anthropic API slowness during incidents; captive portals injecting truncated responses.","solutions":["Retry the usage query with backoff — transient body truncation usually resolves itself","Check network path: curl -v the usage endpoint from the same host and watch for truncation","If it times out consistently, the 10s client timeout is too tight for your latency — report/patch it rather than hammering retries","Disable or bypass HTTP(S)_PROXY for api.anthropic.com if a proxy is mangling bodies"],"exampleFix":"// before: single fetch of usage\nusage, err := auth.FetchAnthropicUsage(ctx, token)\n\n// after: bounded retry for transport-level body failures\nvar usage *auth.AnthropicUsage\nerr := retryN(3, 500*time.Millisecond, func() error {\n    u, e := auth.FetchAnthropicUsage(ctx, token)\n    if u != nil { usage = u }\n    return e\n})","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"var usage *auth.AnthropicUsage\nerr := retryN(3, time.Second, func() error {\n    u, e := fetchUsage(ctx, token)\n    if e != nil && strings.Contains(e.Error(), \"reading usage response\") {\n        return e // transport-level body failure: safe to retry\n    }\n    if u != nil { usage = u }\n    return retryStop{e}\n})","preventionTips":["Wrap usage fetches in bounded retry with backoff","Poll usage sparingly (minutes, not seconds) so flaky reads are rare","Keep the client on a stable network path free of body-truncating proxies"],"tags":["go","network","http","auth","retry"],"backgroundTag":null,"analyzedSha":"49183d7e8daed0dba89ddbb6fcb60089401d9680","analyzedAt":"2026-08-15T21:55:41.315Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}