JuliusBrussee/caveman · error

upstream_proxy : unsupported scheme

Error message

upstream_proxy %q: unsupported scheme %q

What it means

The upstream_proxy config value was parsed as a URL but its scheme is not one of the four the proxy supports (http, https, socks5, socks5h). parseUpstreamProxy accepts "env", "off", or a full proxy URL, and rejects any other scheme because the HTTP transport layer cannot dial through it. This prevents silently configuring a proxy type the proxy will fail to use at request time.

Solutions

  1. Change the proxy URL scheme to one of http, https, socks5, or socks5h.
  2. If no scheme was intended, add the prefix explicitly, e.g. "http://proxy.corp:8080".
  3. If you wanted environment-based discovery instead, set upstream_proxy to "env".
  4. If no proxy is wanted, set upstream_proxy to "off".

Example fix

// before
upstream_proxy = "socks4://127.0.0.1:9050"
// after
upstream_proxy = "socks5://127.0.0.1:9050"
Defensive patterns

Strategy: validation

Validate before calling

u, err := url.Parse(raw)
if err != nil || u.Host == "" {
    return fmt.Errorf("upstream_proxy %q must be \"env\", \"off\" or a proxy URL", raw)
}
switch u.Scheme {
case "http", "https", "socks5", "socks5h":
default:
    return fmt.Errorf("unsupported upstream_proxy scheme %q", u.Scheme)
}

Prevention

When it happens

Trigger: Setting upstream_proxy to a URL whose scheme is not http/https/socks5/socks5h — e.g. "ftp://proxy:21", "quic://...", a URL with an empty scheme like "proxy.corp:8080" (parsed as opaque path, scheme = whole string), or typos like "https//proxy:8080" — then calling config.Load or UpstreamProxyFunc.

Common situations: Typing a host:port without a scheme prefix (url.Parse gives a bogus scheme); copying a PAC or browser proxy string; using a scheme variant like socks4 or http2 that is intentionally unsupported; YAML config edited by hand.

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/357e0370e1fe49eb. Report an issue: GitHub.

Appendix: source

Thrown at proxy/internal/config/config.go:275

func parseUpstreamProxy(raw string) (func(*http.Request) (*url.URL, error), error) {
	raw = strings.TrimSpace(raw)
	switch strings.ToLower(raw) {
	case "", "env":
		// ProxyFromEnvironment snapshots the proxy variables once per process
		// (sync.Once), so a test that t.Setenv's HTTPS_PROXY must build its own
		// httpproxy.Config selector instead — see ssrf_test.go.
		return http.ProxyFromEnvironment, nil
	case "off":
		return nil, nil
	}
	u, err := url.Parse(raw)
	if err != nil || u.Host == "" {
		return nil, fmt.Errorf("upstream_proxy %q must be \"env\", \"off\" or a proxy URL", raw)
	}
	switch u.Scheme {
	case "http", "https", "socks5", "socks5h":
	default:
		return nil, fmt.Errorf("upstream_proxy %q: unsupported scheme %q", raw, u.Scheme)
	}
	// Same selector semantics as env mode: localhost/loopback destinations (an
	// allowlisted Ollama) and NO_PROXY matches are dialed direct rather than
	// handed to a corporate proxy that cannot reach them.
	selector := (&httpproxy.Config{HTTPProxy: raw, HTTPSProxy: raw, NoProxy: env.String("NO_PROXY", env.String("no_proxy", ""))}).ProxyFunc()
	return func(req *http.Request) (*url.URL, error) { return selector(req.URL) }, nil
}

// minAuthTokenBytes is the floor for the inbound shared secret. The token is the
// only gate in front of every configured provider credential once the proxy is
// reachable off-host, so a short one is not a weaker deployment, it is an open one.
const minAuthTokenBytes = 16

// validateAuthToken refuses a token that cannot survive one HTTP header value:
// control bytes terminate the field, and a space would split scheme from value in
// `Authorization: Bearer <token>`. The error never echoes the value — it is a
// secret and this message reaches the proxy log.
func validateAuthToken(token string) error {

View on GitHub (pinned to 3ee70a1026)