sipeed/picoclaw · error
insufficient scope: usage endpoint requires oauth scope
Error message
insufficient scope: usage endpoint requires oauth scope
What it means
The Anthropic usage endpoint answered HTTP 403 (anthropic_usage.go:50): the request authenticated, but the credential's OAuth token lacks the scope required by the usage endpoint. This is a deliberate authorization failure, distinct from a network or parse error, and is non-retryable — retrying the same token always yields 403.
Source
Thrown at pkg/auth/anthropic_usage.go:50
req.Header.Set("Authorization", "Bearer "+token)
req.Header.Set("Anthropic-Version", anthropicAPIVersion)
req.Header.Set("Anthropic-Beta", anthropicBetaHeader)
client := &http.Client{Timeout: 10 * time.Second}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("reading usage response: %w", err)
}
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,View on GitHub (pinned to 49183d7e8d)
Solutions
- Re-authenticate through the current login flow so a fresh token with the usage scope is issued
- Verify in the provider console that your OAuth client requests/is granted the usage scope
- If your plan/credential type does not include usage scope, disable usage polling rather than retrying
- Do not retry in a loop — classify 403 as permanent and surface it to the user
Example fix
// before: poll usage forever with an unscoped token
for { usage, err := fetchUsage(token); if err != nil { continue } }
// after: stop permanently on scope errors
if strings.Contains(err.Error(), "insufficient scope") {
log.Print("token lacks usage scope; re-login required")
return err
} Defensive patterns
Strategy: try-catch
Try / catch
usage, err := fetchUsage(ctx, token)
if err != nil {
if strings.Contains(err.Error(), "insufficient scope") {
// permanent: stop polling, prompt re-login
disableUsagePolling()
promptRelogin()
return err
}
return err
} Prevention
- Authenticate through the flow that grants the usage scope before enabling usage features
- Never auto-retry 403-class authorization errors
- Distinguish 'insufficient scope' (403) from 'request failed (401)' (expired token) in handlers
When it happens
Trigger: Calling the usage fetch with an OAuth credential minted by a login flow that did not request the usage scope; using a token from an OAuth client/app not allow-listed for usage reporting; org policy stripping the scope from issued tokens.
Common situations: Token from an older login (pre-usage-scope); custom OAuth client_id missing the usage scope; Claude Max/Pro subscription vs API-key confusion where usage endpoint is OAuth-only.
Related errors
- usage request failed (%d): %s
- No authorization code received
- HTTP %d: %s
- reading usage response: %w
- parsing usage response: %w
AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15).
Data as JSON: /api/errors/1815ad53a71fa158.
Report an issue: GitHub.