sipeed/picoclaw · error

parsing usage response: %w

Error message

parsing usage response: %w

What it means

json.Unmarshal(body, &result) failed at anthropic_usage.go:64 — the usage endpoint's body was not the expected JSON object with numeric five_hour/seven_day utilization fields. Since the status was 200, this means a 200 response whose body is HTML (proxy login page), truncated JSON from the read, or a schema change (e.g. utilization serialized as a string).

Source

Thrown at pkg/auth/anthropic_usage.go:64

	}

	if resp.StatusCode != http.StatusOK {
		if resp.StatusCode == http.StatusForbidden {
			return nil, fmt.Errorf("insufficient scope: usage endpoint requires oauth scope")
		}
		return nil, fmt.Errorf("usage request failed (%d): %s", resp.StatusCode, string(body))
	}

	var result struct {
		FiveHour struct {
			Utilization float64 `json:"utilization"`
		} `json:"five_hour"`
		SevenDay struct {
			Utilization float64 `json:"utilization"`
		} `json:"seven_day"`
	}
	if err := json.Unmarshal(body, &result); err != nil {
		return nil, fmt.Errorf("parsing usage response: %w", err)
	}

	return &AnthropicUsage{
		FiveHourUtilization: result.FiveHour.Utilization,
		SevenDayUtilization: result.SevenDay.Utilization,
	}, nil
}

View on GitHub (pinned to 49183d7e8d)

Solutions

  1. Log the raw body (it is in your hands at the call site via the error's context or by reproducing with curl) to see whether it is HTML, truncated, or a schema change
  2. Reproduce with curl -H "Authorization: Bearer $TOKEN" against the usage endpoint to inspect the true body
  3. Bypass or configure the intercepting proxy for the Anthropic domain
  4. If the JSON schema genuinely changed, update/pin the client version that matches the API

Example fix

// before: assume body is always the expected shape
json.Unmarshal(body, &result)

// after: sniff non-JSON bodies before decoding
if len(body) == 0 || (body[0] != '{' && body[0] != '[') {
    return nil, fmt.Errorf("usage endpoint returned non-JSON body: %.120s", body)
}
Defensive patterns

Strategy: validation

Validate before calling

// sniff body shape before decoding
func looksLikeJSON(b []byte) bool {
    t := strings.TrimSpace(string(b))
    return strings.HasPrefix(t, "{") || strings.HasPrefix(t, "[")
}

if !looksLikeJSON(body) {
    return nil, fmt.Errorf("usage endpoint returned non-JSON (%.120s); proxy interference?", body)
}

Try / catch

if err := json.Unmarshal(body, &result); err != nil {
    if typeErr, ok := err.(*json.UnmarshalTypeError); ok {
        // 200 body but wrong types (e.g. utilization as string): schema drift
        log.Printf("usage schema changed at field %s: %v", typeErr.Field, typeErr)
    }
    return nil, fmt.Errorf("parsing usage response: %w", err)
}

Prevention

When it happens

Trigger: Transparent proxy returning an HTML block page with 200; body read partially after a mid-stream stall so JSON is cut mid-token; API returning utilization as "0.42" (string) instead of 0.42 (float) — Unmarshal then fails with a type-error pointing at the field.

Common situations: Captive portals / Zscaler-style interceptors; flaky mobile links truncating bodies; Anthropic API schema evolution not yet reflected in this client version.

Related errors


AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15). Data as JSON: /api/errors/dad3ce9b503da548. Report an issue: GitHub.