JuliusBrussee/caveman · error
provider upstream URL scheme is not allowed
Error message
provider %q upstream URL scheme %q is not allowed
What it means
parseBaseURL enforces that each upstream BaseURL is an absolute http(s) URL with a host, and rejects any other scheme (file:, unix:, ftp:, ws:, etc.). Only http and https are safe to hand to the proxy's HTTP client, so anything else fails validation at config time or request time.
Solutions
- Prefix the BaseURL with https:// (or http:// for plain-HTTP local upstreams)
- Use the form http://127.0.0.1:8080 for local services instead of a bare host:port or unix: scheme
- Run the config through ValidateBaseURL at startup to catch bad values before traffic
- If you need a unix socket, use a local HTTP proxy that bridges to it rather than a non-http scheme
Example fix
// before BaseURL: "localhost:8080" // after BaseURL: "http://localhost:8080"
Defensive patterns
Strategy: validation
Validate before calling
u, err := url.Parse(strings.TrimSpace(raw))
if err != nil {
return err
}
if (u.Scheme != "http" && u.Scheme != "https") || u.Host == "" {
return fmt.Errorf("upstream must be an absolute http(s) URL")
} Try / catch
if err := ValidateBaseURL(cfg.BaseURL); err != nil {
return fmt.Errorf("invalid upstream URL for %s: %w", cfg.Provider, err)
} Prevention
- Always include the scheme (https://) in configured URLs
- Run ValidateBaseURL on every upstream entry at startup
- Document that only http/https upstreams are supported
When it happens
Trigger: BaseURL like file:///var/run/sock, localhost:8080 (scheme parsed as 'localhost'), ftp://..., or a URL with an unexpected scheme in CAVE_COMPAT_UPSTREAMS / compat: config; values missing the '://' separator entirely.
Common situations: Omitting https:// when writing the config (host-only strings); trying to point the upstream at a unix socket via a non-http scheme; copying internal URLs with custom schemes.
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
- CAVEMAN_CCR_MAX_BYTES must be a positive integer
- ccr max storage bytes must be positive
- compat upstream name
- compat upstream base_url
- githubapp: app id is required
AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20).
Data as JSON: /api/errors/5abcb9739c468e7f.
Report an issue: GitHub.
Appendix: source
Thrown at proxy/providers/openaicompat/openaicompat.go:520
// a path cannot change route identity after another decoder or proxy hop.
for _, escape := range []string{"%2f", "%5c", "%2e"} {
if strings.Contains(strings.ToLower(path), escape) || strings.Contains(strings.ToLower(rawPath), escape) {
return fmt.Errorf("ambiguous escaped path sequence %s", escape)
}
}
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)