JuliusBrussee/caveman · error
invalid Claude organization id
Error message
invalid Claude organization id
What it means
The org id is interpolated directly into the request path https://claude.ai/api/organizations/<orgID>/usage. Because it builds a URL from untrusted env input, values containing '/' or '..' are rejected — they could escape the intended path segment (path traversal / hitting a different endpoint). This is a validation guard, not a formatting nicety.
Source
Thrown at proxy/internal/store/usage_import.go:134
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)
}
return io.ReadAll(io.LimitReader(resp.Body, 4<<20))
}View on GitHub (pinned to 27d5a3981a)
Solutions
- Set CAVEMAN_CLAUDE_ORG_ID to the bare organization uuid with no scheme, slashes, or dots: export CAVEMAN_CLAUDE_ORG_ID=0f1e2d3c-....
- Strip accidental slashes before export: CAVEMAN_CLAUDE_ORG_ID=${CAVEMAN_CLAUDE_ORG_ID#/}; verify with echo.
- If you only have the full URL, extract the uuid segment (e.g. with parameter expansion or sed) and export just that.
Example fix
# before export CAVEMAN_CLAUDE_ORG_ID="https://claude.ai/api/organizations/0f1e.../usage" # after export CAVEMAN_CLAUDE_ORG_ID="0f1e2d3c-4b5a-6978-8796-a5b4c3d2e1f0"
Defensive patterns
Strategy: validation
Validate before calling
orgID := os.Getenv("CAVEMAN_CLAUDE_ORG_ID")
if strings.Contains(orgID, "/") || strings.Contains(orgID, "..") || orgID == "" {
return fmt.Errorf("CAVEMAN_CLAUDE_ORG_ID must be a bare org uuid, got %q", orgID)
} Type guard
func isBareOrgID(v string) bool {
return v != "" && !strings.Contains(v, "/") && !strings.Contains(v, "..")
} Try / catch
if _, err := s.RefreshClaudeUsageFromEnv(); err != nil {
if strings.Contains(err.Error(), "invalid Claude organization id") {
return configError("CAVEMAN_CLAUDE_ORG_ID must be the bare uuid — no URL, no slashes")
}
return err
} Prevention
- Export only the uuid segment, never a pasted URL.
- Strip trailing slashes in env files.
- Add a startup assertion rejecting '/' and '..' in the org id.
When it happens
Trigger: Setting CAVEMAN_CLAUDE_ORG_ID to a URL, a path fragment ('orgs/123'), a value with a trailing slash, or a copied string that includes '../' — for example pasting the whole organizations URL instead of just the uuid.
Common situations: Pasting 'https://claude.ai/settings/orgs/<uuid>' or '<uuid>/' from the browser address bar instead of the bare uuid; env files that append stray characters; attempting to target a nested API path via the org variable.
Related errors
- cave_memory_tenant_invalid
- cave_memory_agent_invalid
- invalid agent evidence identity
- invalid native session identity
- password must be at least %d bytes
AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15).
Data as JSON: /api/errors/9ddcfc3e9ef73175.
Report an issue: GitHub.