JuliusBrussee/caveman · error

provider upstream URL must be an absolute URL with a host

Error message

provider %q upstream URL must be an absolute URL with a host

What it means

The caveman proxy's OpenAI-compatible adapter validates the configured upstream base URL in parseBaseURL (openaicompat.go:522) before joining request paths onto it. This error fires when the URL either has no scheme (relative URL), or parses to an empty host (e.g. 'https:///v1' or 'http://'). The adapter cannot build a deterministic upstream endpoint without an absolute host, so it fails closed.

Solutions

  1. Add the missing scheme and host so the value is a full absolute URL, e.g. change '/v1' to 'https://api.example.com/v1'.
  2. Check the config file and any CAVE_*_BASE_URL environment variable overrides for a truncated or empty host segment and repair it.
  3. Run the adapter's ValidateBaseURL (ValidateBaseURL(raw, "compat")) at startup or in a unit test to fail fast on the malformed value.

Example fix

// before (caveman.yaml)
base_url: /v1
# after
base_url: https://api.openai-compatible.example.com/v1
Defensive patterns

Strategy: validation

Validate before calling

u, err := url.Parse(strings.TrimSpace(cfg.BaseURL))
if err != nil || !u.IsAbs() || u.Host == "" || u.Hostname() == "" || (u.Scheme != "http" && u.Scheme != "https") {
    return fmt.Errorf("provider %q base URL must be an absolute http(s) URL with a host", name)
}

Type guard

func isValidBaseURL(raw string) bool {
    u, err := url.Parse(strings.TrimSpace(raw))
    return err == nil && u.IsAbs() && u.Host != "" && (u.Scheme == "http" || u.Scheme == "https")
}

Try / catch

base, err := parseBaseURL(cfg.BaseURL, provider)
if err != nil {
    log.Fatalf("invalid base_url for %s: %v — expected https://host[:port]/path", provider, err)
}

Prevention

When it happens

Trigger: Calling ResolveUpstreamURL or ValidateBaseURL when the provider's configured base URL is a relative path like '/v1', a scheme-only string like 'https://', or a URL where the host portion is empty (e.g. 'https:///api').

Common situations: A caveman.yaml compat-provider entry where the base_url was pasted without the 'https://' prefix, an env-var override (e.g. CAVE_..._BASE_URL) left partially filled, or a YAML value starting with '/' interpreted as a path. Also common when a trailing segment was accidentally kept and the host deleted during editing.

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/89077585981d47c6. Report an issue: GitHub.

Appendix: source

Thrown at proxy/providers/openaicompat/openaicompat.go:523

			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)