JuliusBrussee/caveman · error
compat upstream name
Error message
compat upstream name %q must match [a-z0-9][a-z0-9._-]{0,63} What it means
ValidateName enforces the mount-name grammar [a-z0-9][a-z0-9._-]{0,63}: lowercase alphanumeric first character, then lowercase alphanumerics, dots, underscores, or hyphens, max 64 chars. Names outside this grammar fail with this message because the name becomes a URL path segment (/compat/<name>/) and must be safe and unambiguous.
Solutions
- Rename the mount to lowercase alphanumerics with . _ - separators, e.g. "claude-prod".
- Ensure the first character is a lowercase letter or digit.
- Shorten names to 64 characters or fewer.
- Slugify the name (strings.ToLower + replace invalid chars) in config generation tooling.
Example fix
# before name = "Claude_Prod EU" # after name = "claude-prod-eu"
Defensive patterns
Strategy: validation
Validate before calling
var validName = regexp.MustCompile(`^[a-z0-9][a-z0-9._-]{0,63}$`)
if !validName.MatchString(mount.Name) {
return fmt.Errorf("mount name %q must match [a-z0-9][a-z0-9._-]{0,63}", mount.Name)
} Try / catch
if err := openaicompat.ValidateName(name); err != nil {
return nil, fmt.Errorf("rename mount: %w", err)
} Prevention
- Slugify mount names: lowercase, no spaces, first char alphanumeric.
- Cap names at 64 characters.
- Validate names in config CI before deploy.
When it happens
Trigger: A mount name with uppercase letters, spaces, a leading dot/hyphen/underscore, non-ASCII characters, or length > 64 is passed to NewNamedWithWireDialect or listed in config and checked by validateCompat.
Common situations: Human-readable names like "My Upstream" or "Claude_Prod"; names auto-generated with a UUID prefix; env-interpolated names carrying whitespace.
Understand the failure class
Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.
Related errors
- compat upstream name
- wire dialect must be "anthropic" or empty
- CAVEMAN_CCR_MAX_BYTES must be a positive integer
- ccr max storage bytes must be positive
- compat upstream base_url
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/e4c2384cf22e77ef.
Report an issue: GitHub.
Appendix: source
Thrown at proxy/providers/openaicompat/openaicompat.go:422
return fmt.Errorf("header %q cannot be forwarded", name)
}
switch lower {
// Routing/framing, credentials, and fields whose value this proxy
// constructs. x-forwarded-*/forwarded/x-real-ip would let a caller
// choose the client address an upstream rate-limits or allowlists on.
case "host", "connection", "keep-alive", "proxy-connection", "proxy-authorization", "proxy-authenticate", "te", "trailer", "transfer-encoding", "upgrade", "content-length", "expect",
"authorization", "x-api-key", "api-key", "x-goog-api-key", "x-goog-user-project", "cookie", "set-cookie",
"forwarded", "x-forwarded-for", "x-forwarded-host", "x-forwarded-proto", "x-forwarded-port", "x-real-ip",
"user-agent", "content-type":
return fmt.Errorf("header %q cannot be forwarded", name)
}
}
return nil
}
func ValidateName(name string) error {
if !validName.MatchString(name) {
return fmt.Errorf("compat upstream name %q must match [a-z0-9][a-z0-9._-]{0,63}", name)
}
switch name {
case "stub", "openai-compatible":
return fmt.Errorf("compat upstream name %q is reserved", name)
default:
return nil
}
}
func ValidateBaseURL(raw string) error {
_, err := parseBaseURL(raw, "compat")
return err
}
// ResolveUpstreamURL intentionally ignores RouteContext.BaseURL. Named mounts
// are configured as independent static upstreams (`compat:` in standalone or
// CAVE_COMPAT_UPSTREAMS in managed mode); applying the generic project
// openai_compatible override here would collapse every named route onto oneView on GitHub (pinned to 3ee70a1026)