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

  1. Remove the 'user:password@' portion from the base URL and keep only 'scheme://host[:port]/path'.
  2. Pass the credential through the proxy's dedicated credential mechanism (BYOK env key or inbound Authorization/x-api-key) instead of the URL.
  3. 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

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


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)