{"id":"42750b21801559d5","repo":"gofiber/fiber","slug":"failed-to-parse-client-ca-certificate-from-q","errorCode":null,"errorMessage":"failed to parse client CA certificate from %q","messagePattern":"failed to parse client CA certificate from %q","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"listen.go","lineNumber":314,"sourceCode":"\t}\n\n\tserved = true\n\treturn app.server.Serve(ln)\n}\n\nfunc applyClientCert(tlsConfig *tls.Config, certClientFile string) error {\n\tif certClientFile == \"\" {\n\t\treturn nil\n\t}\n\n\tclientCACert, err := os.ReadFile(filepath.Clean(certClientFile))\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to read client CA file %q: %w\", certClientFile, err)\n\t}\n\n\tclientCertPool := x509.NewCertPool()\n\tif ok := clientCertPool.AppendCertsFromPEM(clientCACert); !ok {\n\t\treturn fmt.Errorf(\"failed to parse client CA certificate from %q\", certClientFile)\n\t}\n\n\ttlsConfig.ClientAuth = tls.RequireAndVerifyClientCert\n\ttlsConfig.ClientCAs = clientCertPool\n\n\treturn nil\n}\n\n// Listener serves HTTP requests from the given listener.\n// You should enter custom ListenConfig to customize startup. (prefork, startup message, graceful shutdown...)\nfunc (app *App) Listener(ln net.Listener, config ...ListenConfig) error {\n\tcfg := listenConfigDefault(config...)\n\n\t// Graceful shutdown\n\tif cfg.GracefulContext != nil {\n\t\tctx, cancel := context.WithCancel(cfg.GracefulContext)\n\t\tdefer cancel()\n","sourceCodeStart":296,"sourceCodeEnd":332,"githubUrl":"https://github.com/gofiber/fiber/blob/9a4c7e57fe0b080a04235d28a4b0d2b4b353d58c/listen.go#L296-L332","documentation":"Returned by applyClientCert when the file referenced by the mTLS client CA config was read successfully but crypto/x509's AppendCertsFromPEM rejected its contents. The file must contain one or more PEM-encoded ('-----BEGIN CERTIFICATE-----') CA certificates; anything else (DER bytes, a private key alone, a CRL, or corrupt/truncated PEM) makes the parser return false. Because the value is needed to populate tls.Config.ClientCAs for RequireAndVerifyClientCert, Fiber fails closed and returns the error at server startup rather than silently weakening client verification.","triggerScenarios":"Configuring ListenConfig with a ClientCertFile path whose bytes are not parseable PEM certificates (e.g. a DER-encoded .cer, a PEM containing only a private key, an empty file, or a file with a broken '-----END CERTIFICATE-----' boundary). AppendCertsFromPEM returns false, so applyClientCert returns this exact error before any listener is created.","commonSituations":"Exporting a CA from a browser or Windows certmgr often yields DER; ops copies the wrong file (leaf cert instead of CA, or a combined bundle that starts with a key); CI mounts an empty secret because the Kubernetes Secret name was mistyped; converting formats with openssl forgets the -outform PEM flag.","solutions":["Verify the file is PEM: run 'openssl x509 -in <file> -noout -text' (PEM works, DER errors); if it prints 'unable to load certificate', convert with 'openssl x509 -inform DER -in <file> -out <file>.pem'.","Confirm the file contains a CA certificate (has BASICCONSTRAINTS CA:TRUE) and not just a leaf or a key: 'openssl x509 -in <file> -noout -text | grep -i CA:'.","Check for truncation or copy/paste corruption: 'grep -c BEGIN CERTIFICATE <file>' should be >= 1 and each BEGIN must have a matching END.","Point ListenConfig.ClientCertFile at the corrected PEM path and restart so applyClientCert re-parses."],"exampleFix":"// before\napp.Listen(\":443\", fiber.ListenConfig{\n  TLSConfig: &tls.Config{}, // ClientCertFile pointed at a DER .cer\n  ClientCertFile: \"/etc/ssl/client-ca.cer\",\n})\n\n// after: convert to PEM and supply a CA bundle\n// $ openssl x509 -inform DER -in client-ca.cer -out client-ca.pem\napp.Listen(\":443\", fiber.ListenConfig{\n  TLSConfig:      &tls.Config{},\n  ClientCertFile: \"/etc/ssl/client-ca.pem\",\n})","handlingStrategy":"validation","validationCode":"// Validate the client CA file is PEM-parseable before calling app.Listen.\nfunc validateClientCAPEM(path string) error {\n    b, err := os.ReadFile(filepath.Clean(path))\n    if err != nil {\n        return fmt.Errorf(\"read CA file: %w\", err)\n    }\n    pool := x509.NewCertPool()\n    if !pool.AppendCertsFromPEM(b) {\n        return fmt.Errorf(\"file %q is not PEM-encoded CA certificate(s)\", path)\n    }\n    // optional: ensure at least one CA:TRUE cert\n    return nil\n}\n\n// at startup:\nif err := validateClientCAPEM(cfg.ClientCertFile); err != nil {\n    log.Fatal(err)\n}","typeGuard":"null","tryCatchPattern":"null","preventionTips":["Generate/convert CA material with openssl using explicit -inform/-outform PEM.","Keep CA PEM files in a dedicated directory and lint them in CI with 'openssl x509 -in <f> -noout'.","Treat client CA config as code: store it in version control and review changes.","For Kubernetes, use a configmap/sealed-secret and assert non-empty + PEM header in an init container."],"tags":["tls","mtls","certificates","pem","startup","config"],"analyzedSha":"9a4c7e57fe0b080a04235d28a4b0d2b4b353d58c","analyzedAt":"2026-08-04T21:44:03.395Z","schemaVersion":2}