JuliusBrussee/caveman · error

Claude usage refresh needs CAVEMAN_CLAUDE_USAGE_JSON or…

Error message

Claude usage refresh needs CAVEMAN_CLAUDE_USAGE_JSON or CAVEMAN_CLAUDE_SESSION_KEY plus CAVEMAN_CLAUDE_ORG_ID

What it means

fetchClaudeUsageJSON requires either CAVEMAN_CLAUDE_USAGE_JSON with inline data or both CAVEMAN_CLAUDE_SESSION_KEY and CAVEMAN_CLAUDE_ORG_ID to fetch usage from claude.ai. When the session key or org id is missing/empty, refresh cannot proceed and throws this error instead of making a doomed request.

Solutions

  1. Export both CAVEMAN_CLAUDE_SESSION_KEY and CAVEMAN_CLAUDE_ORG_ID
  2. Alternatively set CAVEMAN_CLAUDE_USAGE_JSON with the usage document to skip fetching
  3. Check env var spelling in your shell profile / CI secrets config
  4. Prefer inline JSON in air-gapped environments where claude.ai is unreachable

Example fix

// before
export CAVEMAN_CLAUDE_SESSION_KEY=sk-...   # ORG_ID missing
// after
export CAVEMAN_CLAUDE_SESSION_KEY=sk-...
export CAVEMAN_CLAUDE_ORG_ID=org-abc123
Defensive patterns

Strategy: validation

Validate before calling

missing := []string{}
if os.Getenv("CAVEMAN_CLAUDE_USAGE_JSON") == "" {
	if os.Getenv("CAVEMAN_CLAUDE_SESSION_KEY") == "" { missing = append(missing, "CAVEMAN_CLAUDE_SESSION_KEY") }
	if os.Getenv("CAVEMAN_CLAUDE_ORG_ID") == "" { missing = append(missing, "CAVEMAN_CLAUDE_ORG_ID") }
}
if len(missing) > 0 { return fmt.Errorf("missing env: %v", missing) }

Try / catch

if err := runUsage(); err != nil {
	if strings.Contains(err.Error(), "needs CAVEMAN_CLAUDE") {
		// print setup instructions
	}
}

Prevention

When it happens

Trigger: Running the usage refresh (runUsage -> RefreshClaudeUsageFromEnv) with neither CAVEMAN_CLAUDE_USAGE_JSON set nor the CAVEMAN_CLAUDE_SESSION_KEY/CAVEMAN_CLAUDE_ORG_ID pair complete — e.g. only one of the two env vars set, or both empty.

Common situations: Fresh machine or CI where Claude credentials were never exported; setting SESSION_KEY but forgetting ORG_ID; typo'd env var names; secrets stripped by the deployment environment.

Understand the failure class

Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20). Data as JSON: /api/errors/3eef29d0b056fed1. Report an issue: GitHub.

Appendix: source

Thrown at proxy/internal/store/usage_import.go:131

		raw = string(fetched)
	}
	var v any
	if err := json.Unmarshal([]byte(raw), &v); err != nil {
		return ImportSummary{}, fmt.Errorf("parse Claude usage JSON: %w", err)
	}
	quotas := quotaEventsFromAny("anthropic", "claude_usage_link", "linked_api", time.Now().UTC().Format(time.RFC3339), v)
	n, err := s.InsertQuotaEvents(quotas)
	if err != nil {
		return ImportSummary{}, err
	}
	return ImportSummary{Source: "claude", QuotaImported: n, Basis: "linked_api"}, nil
}

func fetchClaudeUsageJSON() ([]byte, error) {
	sessionKey := os.Getenv("CAVEMAN_CLAUDE_SESSION_KEY")
	orgID := os.Getenv("CAVEMAN_CLAUDE_ORG_ID")
	if sessionKey == "" || orgID == "" {
		return nil, fmt.Errorf("Claude usage refresh needs CAVEMAN_CLAUDE_USAGE_JSON or CAVEMAN_CLAUDE_SESSION_KEY plus CAVEMAN_CLAUDE_ORG_ID")
	}
	if strings.Contains(orgID, "/") || strings.Contains(orgID, "..") {
		return nil, fmt.Errorf("invalid Claude organization id")
	}
	req, err := http.NewRequest("GET", "https://claude.ai/api/organizations/"+orgID+"/usage", nil)
	if err != nil {
		return nil, err
	}
	req.Header.Set("accept", "application/json")
	req.Header.Set("cookie", "sessionKey="+sessionKey)
	client := http.Client{Timeout: 15 * time.Second}
	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()
	if resp.StatusCode < 200 || resp.StatusCode >= 300 {
		return nil, fmt.Errorf("Claude usage request failed with HTTP %d", resp.StatusCode)

View on GitHub (pinned to 3ee70a1026)