{"record":{"id":"357e0370e1fe49eb","repo":"JuliusBrussee/caveman","slug":"upstream-proxy-q-unsupported-scheme-q","errorCode":null,"errorMessage":"upstream_proxy %q: unsupported scheme %q","messagePattern":"upstream_proxy %q: unsupported scheme %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"proxy/internal/config/config.go","lineNumber":275,"sourceCode":"func parseUpstreamProxy(raw string) (func(*http.Request) (*url.URL, error), error) {\n\traw = strings.TrimSpace(raw)\n\tswitch strings.ToLower(raw) {\n\tcase \"\", \"env\":\n\t\t// ProxyFromEnvironment snapshots the proxy variables once per process\n\t\t// (sync.Once), so a test that t.Setenv's HTTPS_PROXY must build its own\n\t\t// httpproxy.Config selector instead — see ssrf_test.go.\n\t\treturn http.ProxyFromEnvironment, nil\n\tcase \"off\":\n\t\treturn nil, nil\n\t}\n\tu, err := url.Parse(raw)\n\tif err != nil || u.Host == \"\" {\n\t\treturn nil, fmt.Errorf(\"upstream_proxy %q must be \\\"env\\\", \\\"off\\\" or a proxy URL\", raw)\n\t}\n\tswitch u.Scheme {\n\tcase \"http\", \"https\", \"socks5\", \"socks5h\":\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"upstream_proxy %q: unsupported scheme %q\", raw, u.Scheme)\n\t}\n\t// Same selector semantics as env mode: localhost/loopback destinations (an\n\t// allowlisted Ollama) and NO_PROXY matches are dialed direct rather than\n\t// handed to a corporate proxy that cannot reach them.\n\tselector := (&httpproxy.Config{HTTPProxy: raw, HTTPSProxy: raw, NoProxy: env.String(\"NO_PROXY\", env.String(\"no_proxy\", \"\"))}).ProxyFunc()\n\treturn func(req *http.Request) (*url.URL, error) { return selector(req.URL) }, nil\n}\n\n// minAuthTokenBytes is the floor for the inbound shared secret. The token is the\n// only gate in front of every configured provider credential once the proxy is\n// reachable off-host, so a short one is not a weaker deployment, it is an open one.\nconst minAuthTokenBytes = 16\n\n// validateAuthToken refuses a token that cannot survive one HTTP header value:\n// control bytes terminate the field, and a space would split scheme from value in\n// `Authorization: Bearer <token>`. The error never echoes the value — it is a\n// secret and this message reaches the proxy log.\nfunc validateAuthToken(token string) error {","sourceCodeStart":257,"sourceCodeEnd":293,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/proxy/internal/config/config.go#L257-L293","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Change the proxy URL scheme to one of http, https, socks5, or socks5h.","If no scheme was intended, add the prefix explicitly, e.g. \"http://proxy.corp:8080\".","If you wanted environment-based discovery instead, set upstream_proxy to \"env\".","If no proxy is wanted, set upstream_proxy to \"off\"."],"exampleFix":"// before\nupstream_proxy = \"socks4://127.0.0.1:9050\"\n// after\nupstream_proxy = \"socks5://127.0.0.1:9050\"","handlingStrategy":"validation","validationCode":"u, err := url.Parse(raw)\nif err != nil || u.Host == \"\" {\n    return fmt.Errorf(\"upstream_proxy %q must be \\\"env\\\", \\\"off\\\" or a proxy URL\", raw)\n}\nswitch u.Scheme {\ncase \"http\", \"https\", \"socks5\", \"socks5h\":\ndefault:\n    return fmt.Errorf(\"unsupported upstream_proxy scheme %q\", u.Scheme)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always include an explicit scheme prefix in proxy URLs (http://, socks5h://).","Keep a config template with valid upstream_proxy examples.","Validate proxy config in CI before deployment by calling Load."],"tags":["config","proxy","url-scheme"],"backgroundTag":"invalid-url-format","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}