paperclipai/paperclip · error · Error
anthropic usage api returned ${resp.status}
Error message
anthropic usage api returned ${resp.status} What it means
Thrown by fetchClaudeQuota when the Anthropic OAuth usage endpoint (https://api.anthropic.com/api/oauth/usage) returns a non-OK HTTP status. The bearer token was sent; the server responded, but not with 200, so the body is not parsed as a quota payload and the raw status code is surfaced for diagnosis.
Source
Thrown at packages/adapters/claude-local/src/server/quota.ts:219
/** fetch with an abort-based timeout so a hanging provider api doesn't block the response indefinitely */
export async function fetchWithTimeout(url: string, init: RequestInit, ms = 8000): Promise<Response> {
const controller = new AbortController();
const timer = setTimeout(() => controller.abort(), ms);
try {
return await fetch(url, { ...init, signal: controller.signal });
} finally {
clearTimeout(timer);
}
}
export async function fetchClaudeQuota(token: string): Promise<QuotaWindow[]> {
const resp = await fetchWithTimeout("https://api.anthropic.com/api/oauth/usage", {
headers: {
Authorization: `Bearer ${token}`,
"anthropic-beta": "oauth-2025-04-20",
},
});
if (!resp.ok) throw new Error(`anthropic usage api returned ${resp.status}`);
const body = (await resp.json()) as AnthropicUsageResponse;
const windows: QuotaWindow[] = [];
if (body.five_hour != null) {
windows.push({
label: "Current session",
usedPercent: toPercent(body.five_hour.utilization),
resetsAt: body.five_hour.resets_at ?? null,
valueLabel: null,
detail: null,
});
}
if (body.seven_day != null) {
windows.push({
label: "Current week (all models)",
usedPercent: toPercent(body.seven_day.utilization),
resetsAt: body.seven_day.resets_at ?? null,
valueLabel: null,View on GitHub (pinned to 67001ec6eb)
Solutions
- Refresh the Claude OAuth credentials: run `claude login` so readClaudeToken returns a fresh access token.
- Map the status code: 401/403 -> re-auth; 429 -> retry with backoff; 5xx -> transient, retry later.
- Confirm the token has the expected OAuth scopes for the usage endpoint.
- If using the quota-probe CLI, pass --cli-only to bypass the OAuth path and use the CLI-based quota source instead.
Example fix
// before const windows = await fetchClaudeQuota(staleToken); // after // run `claude login` to refresh, then: const token = await readClaudeToken(); const windows = await fetchClaudeQuota(token);
Defensive patterns
Strategy: try-catch
Try / catch
try {
const windows = await fetchClaudeQuota(token);
} catch (err) {
const m = err.message.match(/returned (\d+)/);
if (m) {
const status = Number(m[1]);
if (status === 401 || status === 403) { /* re-auth */ }
if (status === 429) { /* back off and retry */ }
}
throw err;
} Prevention
- Refresh Claude OAuth tokens proactively before expiry.
- Treat 401/403 as re-auth signal and 429/5xx as retry-with-backoff.
- Provide a fallback quota source (CLI probe) when the OAuth endpoint is unavailable.
When it happens
Trigger: Calling fetchClaudeQuota(token) where the fetch resolves but resp.ok is false. Common status codes: 401 (token expired/revoked), 403 (scope/permission), 429 (rate limited), 5xx (upstream outage), or 404 if the endpoint path changed.
Common situations: Claude OAuth token past its refresh window; an organization whose plan disables the usage endpoint; transient Anthropic API outage; running in a region that gets rate-limited; token from a different Anthropic account tier.
Related errors
- Choose either --oauth-only or --cli-only, not both.
- Could not parse Claude CLI usage output.
- Claude CLI usage probe ended before rendering usage.
- chatgpt wham api returned ${resp.status}
- Request failed: ${response.status}
AI-assisted analysis of paperclipai/paperclip@67001ec6eb (2026-08-12).
Data as JSON: /api/errors/51581df2b8f0958f.
Report an issue: GitHub.