{"record":{"id":"8d0abc3152eb37f1","repo":"fatedier/frp","slug":"failed-to-parse-oidc-ca-certificate-from-file-q","errorCode":null,"errorMessage":"failed to parse OIDC CA certificate from file %q","messagePattern":"failed to parse OIDC CA certificate from file %q","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/auth/oidc.go","lineNumber":56,"sourceCode":"func createOIDCHTTPClient(trustedCAFile string, insecureSkipVerify bool, proxyURL string) (*http.Client, error) {\n\t// Clone the default transport to get all reasonable defaults\n\ttransport := http.DefaultTransport.(*http.Transport).Clone()\n\n\t// Configure TLS settings\n\tif trustedCAFile != \"\" || insecureSkipVerify {\n\t\ttlsConfig := &tls.Config{\n\t\t\tInsecureSkipVerify: insecureSkipVerify,\n\t\t}\n\n\t\tif trustedCAFile != \"\" && !insecureSkipVerify {\n\t\t\tcaCert, err := os.ReadFile(trustedCAFile)\n\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}","sourceCodeStart":38,"sourceCodeEnd":74,"githubUrl":"https://github.com/fatedier/frp/blob/6c8a8d0a97d03b44e9528d30b30c70cb9d61b405/pkg/auth/oidc.go#L38-L74","documentation":"The OIDC trusted CA file was read successfully but x509.NewCertPool().AppendCertsFromPEM rejected its contents: no PEM-encoded certificate blocks could be parsed from the bytes. This validates content, not access; the file exists but is not a usable CA bundle.","triggerScenarios":"oidc.trustedCAFile contains only a private key or leaf cert, a DER (binary) certificate, stray text around the PEM blocks, or was truncated or copied with formatting damage.","commonSituations":"Pointing trustedCAFile at a TLS key file instead of the CA cert; DER certificate not converted to PEM; copy/paste artifacts (missing BEGIN/END lines, CRLF, escaped newlines); empty file.","solutions":["Inspect the file: it must contain '-----BEGIN CERTIFICATE-----' blocks; re-export the CA in PEM.","If you have DER, convert it: openssl x509 -inform der -in ca.der -out ca.pem.","Validate before starting frps: openssl x509 -in ca.pem -noout must succeed for each block.","Ensure the file holds the CA or full chain, not just the server key."],"exampleFix":"# verify/convert before starting frps\nopenssl x509 -in /etc/frp/oidc-ca.pem -noout || \\\n  openssl x509 -inform der -in /etc/frp/oidc-ca.der -out /etc/frp/oidc-ca.pem","handlingStrategy":"validation","validationCode":"pemBytes, err := os.ReadFile(cfg.Auth.OIDC.TrustedCAFile)\nif err == nil && !x509.NewCertPool().AppendCertsFromPEM(pemBytes) {\n    return fmt.Errorf(\"OIDC CA file is not valid PEM: %s\", cfg.Auth.OIDC.TrustedCAFile)\n}","typeGuard":"func isPEMCertificateFile(path string) bool {\n    b, err := os.ReadFile(path)\n    if err != nil {\n        return false\n    }\n    return x509.NewCertPool().AppendCertsFromPEM(b)\n}","tryCatchPattern":null,"preventionTips":["Distribute CA files via config management, never copy/paste","Validate with `openssl x509 -in file -noout` in CI","Convert DER to PEM explicitly when receiving certs from vendors"],"tags":["auth","oidc","tls","certificate","config"],"backgroundTag":null,"analyzedSha":"6c8a8d0a97d03b44e9528d30b30c70cb9d61b405","analyzedAt":"2026-08-15T06:53:27.215Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}