JuliusBrussee/caveman · error
provider upstream URL must not include userinfo
Error message
provider %q upstream URL must not include userinfo
What it means
parseBaseURL rejects an upstream base URL that embeds userinfo (an 'user:password@' component before the host), openaicompat.go:525. Credentials in the base URL would be silently forwarded and joined into every upstream request, leaking them into logs and metering paths. The adapter strips nothing, so it refuses the value outright.
Solutions
- Remove the 'user:password@' portion from the base URL and keep only 'scheme://host[:port]/path'.
- Pass the credential through the proxy's dedicated credential mechanism (BYOK env key or inbound Authorization/x-api-key) instead of the URL.
- Re-run ValidateBaseURL on the cleaned value to confirm it passes.
Example fix
// before base_url: https://sk-abc123@api.example.com/v1 // after base_url: https://api.example.com/v1 # supply the key via the provider credential/env-key resolution instead
Defensive patterns
Strategy: validation
Validate before calling
if u, err := url.Parse(raw); err == nil && u.User != nil {
return fmt.Errorf("base URL must not contain user:pass@ — move the credential to the auth mechanism")
} Type guard
func hasUserInfo(raw string) bool {
u, err := url.Parse(raw)
return err == nil && u.User != nil
} Try / catch
if err := ValidateBaseURL(raw); err != nil {
if strings.Contains(err.Error(), "userinfo") {
log.Fatal("strip the user:token@ prefix from base_url and configure the key via credentials instead")
}
log.Fatal(err)
} Prevention
- Never embed API keys in URLs, even for self-hosted gateways that accept key@host.
- Store provider keys in env-based BYOK resolution or the request credential header, not the base URL.
- Grep config files for the '@' character inside base_url values during review.
When it happens
Trigger: Configure a compat provider with a base URL such as 'https://user:token@api.example.com/v1' or 'https://apikey@api.example.com' and then call ResolveUpstreamURL or ValidateBaseURL.
Common situations: Copying a curl-style credentialized URL from vendor docs or an old client config; some self-hosted gateways (LiteLLM, one-api) document 'key@host' style URLs; users also embed tokens this way to 'remember' them.
Understand the failure class
Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.
Related errors
- provider upstream URL path rejected
- ssrf: credentials embedded in URL are forbidden
- ssrf: host is blocked (loopback)
- ambiguous escaped path sequence
- awscreds: AWS_CONTAINER_CREDENTIALS_FULL_URI is not a valid…
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/b90a1c55041d511d.
Report an issue: GitHub.
Appendix: source
Thrown at proxy/providers/openaicompat/openaicompat.go:526
return nil
}
func parseBaseURL(raw, provider string) (*url.URL, error) {
if strings.TrimSpace(raw) == "" {
return nil, fmt.Errorf("provider %q has no configured upstream URL", provider)
}
u, err := url.Parse(strings.TrimSpace(raw))
if err != nil {
return nil, err
}
if u.Scheme != "http" && u.Scheme != "https" {
return nil, fmt.Errorf("provider %q upstream URL scheme %q is not allowed", provider, u.Scheme)
}
if !u.IsAbs() || u.Host == "" || u.Hostname() == "" {
return nil, fmt.Errorf("provider %q upstream URL must be an absolute URL with a host", provider)
}
if u.User != nil {
return nil, fmt.Errorf("provider %q upstream URL must not include userinfo", provider)
}
if u.Fragment != "" {
return nil, fmt.Errorf("provider %q upstream URL must not include a fragment", provider)
}
if err := validatePathComponents(u.Path, u.RawPath); err != nil {
return nil, fmt.Errorf("provider %q upstream URL path rejected: %w", provider, err)
}
return u, nil
}
View on GitHub (pinned to 3ee70a1026)