{"record":{"id":"a2bb99381940fd66","repo":"fatedier/frp","slug":"failed-to-parse-oidc-proxy-url-q-w","errorCode":null,"errorMessage":"failed to parse OIDC proxy URL %q: %w","messagePattern":"failed to parse OIDC proxy URL %q: %w","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/auth/oidc.go","lineNumber":68,"sourceCode":"\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"failed to read OIDC CA certificate file %q: %w\", trustedCAFile, err)\n\t\t\t}\n\n\t\t\tcaCertPool := x509.NewCertPool()\n\t\t\tif !caCertPool.AppendCertsFromPEM(caCert) {\n\t\t\t\treturn nil, fmt.Errorf(\"failed to parse OIDC CA certificate from file %q\", trustedCAFile)\n\t\t\t}\n\n\t\t\ttlsConfig.RootCAs = caCertPool\n\t\t}\n\t\ttransport.TLSClientConfig = tlsConfig\n\t}\n\n\t// Configure proxy settings\n\tif proxyURL != \"\" {\n\t\tparsedURL, err := url.Parse(proxyURL)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"failed to parse OIDC proxy URL %q: %w\", proxyURL, err)\n\t\t}\n\t\ttransport.Proxy = http.ProxyURL(parsedURL)\n\t} else {\n\t\t// Explicitly disable proxy to override DefaultTransport's ProxyFromEnvironment\n\t\ttransport.Proxy = nil\n\t}\n\n\treturn &http.Client{Transport: transport}, nil\n}\n\n// nonCachingTokenSource wraps a clientcredentials.Config to fetch a fresh\n// token on every call. This is used as a fallback when the OIDC provider\n// does not return expires_in, which would cause a caching TokenSource to\n// hold onto a stale token forever.\ntype nonCachingTokenSource struct {\n\tcfg *clientcredentials.Config\n\tctx context.Context\n}","sourceCodeStart":50,"sourceCodeEnd":86,"githubUrl":"https://github.com/fatedier/frp/blob/6c8a8d0a97d03b44e9528d30b30c70cb9d61b405/pkg/auth/oidc.go#L50-L86","documentation":"frpc's OIDC authentication builds a dedicated HTTP client for the token endpoint. When oidc.proxyURL is set, that string is passed to Go's url.Parse; if parsing fails the client construction aborts with this wrapped error. url.Parse only rejects structurally invalid URLs (e.g. control characters, missing scheme like 'host:8080' being misread), so in practice the configured value is malformed rather than merely unreachable.","triggerScenarios":"Client config with authentication.oidc enabled and oidc.proxyURL set to a value Go cannot parse: 'socks5 :1080' (space instead of ://), '127.0.0.1:8080' (parsed as scheme '127.0.0.1'), a URL containing spaces or control characters, or a scheme with invalid characters.","commonSituations":"Routing frpc's OIDC token fetch through a corporate proxy; users write a bare host:port without the http:// scheme, or copy a proxy address with a typo; recently migrating from env-var HTTP_PROXY to the explicit oidc.proxyURL field.","solutions":["Correct the proxy URL to a fully qualified form with scheme and host, e.g. http://proxy.example.com:8080 or socks5://127.0.0.1:1080","Verify scheme spelled exactly http, https, or socks5 followed by '://'","Remove any surrounding quotes, spaces, or stray characters from the config value","Test the value in isolation: url.Parse(\"socks5://127.0.0.1:1080\") must succeed"],"exampleFix":"// frpc.toml before\nauthentication.method = \"oidc\"\nauthentication.oidc.proxyURL = \"127.0.0.1:8080\"\n\n// after\nauthentication.method = \"oidc\"\nauthentication.oidc.proxyURL = \"http://127.0.0.1:8080\"","handlingStrategy":"validation","validationCode":"u, err := url.Parse(proxyURL)\nif err != nil || u.Scheme == \"\" || u.Host == \"\" {\n    return fmt.Errorf(\"oidc.proxyURL must be a full URL like http://host:port, got %q\", proxyURL)\n}","typeGuard":null,"tryCatchPattern":"if err := validateProxyURL(cfg.ProxyURL); err != nil { return err } // fail fast before NewOidcAuthProvider","preventionTips":["Always write proxy URLs with an explicit scheme (http:// or socks5://)","Validate the URL with url.Parse and a non-empty Host check in config-validation tooling","Keep proxy addresses in one config variable instead of duplicating them"],"tags":["frp","oidc","proxy","config","url-parsing"],"backgroundTag":null,"analyzedSha":"6c8a8d0a97d03b44e9528d30b30c70cb9d61b405","analyzedAt":"2026-08-15T06:53:27.215Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}