{"record":{"id":"3eef29d0b056fed1","repo":"JuliusBrussee/caveman","slug":"claude-usage-refresh-needs-caveman-claude-usage-js","errorCode":null,"errorMessage":"Claude usage refresh needs CAVEMAN_CLAUDE_USAGE_JSON or CAVEMAN_CLAUDE_SESSION_KEY plus CAVEMAN_CLAUDE_ORG_ID","messagePattern":"Claude usage refresh needs CAVEMAN_CLAUDE_USAGE_JSON or CAVEMAN_CLAUDE_SESSION_KEY plus CAVEMAN_CLAUDE_ORG_ID","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"proxy/internal/store/usage_import.go","lineNumber":131,"sourceCode":"\t\traw = string(fetched)\n\t}\n\tvar v any\n\tif err := json.Unmarshal([]byte(raw), &v); err != nil {\n\t\treturn ImportSummary{}, fmt.Errorf(\"parse Claude usage JSON: %w\", err)\n\t}\n\tquotas := quotaEventsFromAny(\"anthropic\", \"claude_usage_link\", \"linked_api\", time.Now().UTC().Format(time.RFC3339), v)\n\tn, err := s.InsertQuotaEvents(quotas)\n\tif err != nil {\n\t\treturn ImportSummary{}, err\n\t}\n\treturn ImportSummary{Source: \"claude\", QuotaImported: n, Basis: \"linked_api\"}, nil\n}\n\nfunc fetchClaudeUsageJSON() ([]byte, error) {\n\tsessionKey := os.Getenv(\"CAVEMAN_CLAUDE_SESSION_KEY\")\n\torgID := os.Getenv(\"CAVEMAN_CLAUDE_ORG_ID\")\n\tif sessionKey == \"\" || orgID == \"\" {\n\t\treturn nil, fmt.Errorf(\"Claude usage refresh needs CAVEMAN_CLAUDE_USAGE_JSON or CAVEMAN_CLAUDE_SESSION_KEY plus CAVEMAN_CLAUDE_ORG_ID\")\n\t}\n\tif strings.Contains(orgID, \"/\") || strings.Contains(orgID, \"..\") {\n\t\treturn nil, fmt.Errorf(\"invalid Claude organization id\")\n\t}\n\treq, err := http.NewRequest(\"GET\", \"https://claude.ai/api/organizations/\"+orgID+\"/usage\", nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treq.Header.Set(\"accept\", \"application/json\")\n\treq.Header.Set(\"cookie\", \"sessionKey=\"+sessionKey)\n\tclient := http.Client{Timeout: 15 * 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\tif resp.StatusCode < 200 || resp.StatusCode >= 300 {\n\t\treturn nil, fmt.Errorf(\"Claude usage request failed with HTTP %d\", resp.StatusCode)","sourceCodeStart":113,"sourceCodeEnd":149,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/proxy/internal/store/usage_import.go#L113-L149","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Export both CAVEMAN_CLAUDE_SESSION_KEY and CAVEMAN_CLAUDE_ORG_ID","Alternatively set CAVEMAN_CLAUDE_USAGE_JSON with the usage document to skip fetching","Check env var spelling in your shell profile / CI secrets config","Prefer inline JSON in air-gapped environments where claude.ai is unreachable"],"exampleFix":"// before\nexport CAVEMAN_CLAUDE_SESSION_KEY=sk-...   # ORG_ID missing\n// after\nexport CAVEMAN_CLAUDE_SESSION_KEY=sk-...\nexport CAVEMAN_CLAUDE_ORG_ID=org-abc123","handlingStrategy":"validation","validationCode":"missing := []string{}\nif os.Getenv(\"CAVEMAN_CLAUDE_USAGE_JSON\") == \"\" {\n\tif os.Getenv(\"CAVEMAN_CLAUDE_SESSION_KEY\") == \"\" { missing = append(missing, \"CAVEMAN_CLAUDE_SESSION_KEY\") }\n\tif os.Getenv(\"CAVEMAN_CLAUDE_ORG_ID\") == \"\" { missing = append(missing, \"CAVEMAN_CLAUDE_ORG_ID\") }\n}\nif len(missing) > 0 { return fmt.Errorf(\"missing env: %v\", missing) }","typeGuard":null,"tryCatchPattern":"if err := runUsage(); err != nil {\n\tif strings.Contains(err.Error(), \"needs CAVEMAN_CLAUDE\") {\n\t\t// print setup instructions\n\t}\n}","preventionTips":["Document required env vars in setup docs and CI secrets","Check env presence at process startup with a config linter","Prefer a .env file loader with required-key validation"],"tags":["environment","configuration","usage-import"],"backgroundTag":"missing-env-var","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}