{"id":"4258dd45bc41421e","repo":"jackc/pgx","slug":"unable-to-add-ca-to-cert-pool","errorCode":null,"errorMessage":"unable to add CA to cert pool","messagePattern":"unable to add CA to cert pool","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pgconn/config.go","lineNumber":856,"sourceCode":"\t\t\tvar err error\n\n\t\t\tcaCertPool, err = x509.SystemCertPool()\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"unable to load system certificate pool: %w\", err)\n\t\t\t}\n\n\t\t\tsslmode = \"verify-full\"\n\t\t} else {\n\t\t\tcaCertPool = x509.NewCertPool()\n\n\t\t\tcaPath := sslrootcert\n\t\t\tcaCert, err := os.ReadFile(caPath)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"unable to read CA file: %w\", err)\n\t\t\t}\n\n\t\t\tif !caCertPool.AppendCertsFromPEM(caCert) {\n\t\t\t\treturn nil, errors.New(\"unable to add CA to cert pool\")\n\t\t\t}\n\t\t}\n\n\t\ttlsConfig.RootCAs = caCertPool\n\t\ttlsConfig.ClientCAs = caCertPool\n\t}\n\n\tswitch sslmode {\n\tcase \"disable\":\n\t\treturn []*tls.Config{nil}, nil\n\tcase \"allow\", \"prefer\":\n\t\ttlsConfig.InsecureSkipVerify = true\n\tcase \"require\":\n\t\t// According to PostgreSQL documentation, if a root CA file exists,\n\t\t// the behavior of sslmode=require should be the same as that of verify-ca\n\t\t//\n\t\t// See https://www.postgresql.org/docs/current/libpq-ssl.html\n\t\tif sslrootcert != \"\" {","sourceCodeStart":838,"sourceCodeEnd":874,"githubUrl":"https://github.com/jackc/pgx/blob/ec1a0befd22592cffffdeeb0a50311b506372f4c/pgconn/config.go#L838-L874","documentation":"Returned by configTLS when x509.CertPool.AppendCertsFromPEM returns false for the sslrootcert file. AppendCertsFromPEM returns false only when the PEM data contains no parseable certificates, so the file is empty, not PEM, or corrupted. The TLS config cannot be built without a valid CA, so connection setup aborts.","triggerScenarios":"Setting sslrootcert to a path whose contents are not valid PEM certificates (e.g. a DER-encoded cert, a private key file, random text, or an empty file). Read succeeds but AppendCertsFromPEM fails.","commonSituations":"Pointing sslrootcert at a .key file by mistake; downloading a cert in DER instead of PEM; cert file truncated to zero bytes; copy-paste error inserting the cert into the file.","solutions":["Ensure sslrootcert points to a PEM-encoded CA certificate bundle (BEGIN CERTIFICATE blocks).","If you have a DER cert, convert it: 'openssl x509 -inform der -in ca.der -out ca.pem'.","Verify the file with 'openssl x509 -in ca.pem -noout -text' before using it.","Use sslrootcert=system to rely on the OS trust store when appropriate."],"exampleFix":"# before: pointed at a DER file or wrong file\nsslrootcert=/etc/ssl/db-ca.der\n\n# after: PEM-encoded CA\nopenssl x509 -inform der -in /etc/ssl/db-ca.der -out /etc/ssl/db-ca.pem\nsslrootcert=/etc/ssl/db-ca.pem","handlingStrategy":"validation","validationCode":"// Confirm the sslrootcert file is valid PEM with at least one cert before connecting.\nfunc validateRootCertPEM(path string) error {\n    data, err := os.ReadFile(path)\n    if err != nil {\n        return err\n    }\n    pool := x509.NewCertPool()\n    if !pool.AppendCertsFromPEM(data) {\n        return fmt.Errorf(\"%s contains no PEM-encoded certificates\", path)\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"if _, err := pgx.ParseConfig(dsn); err != nil {\n    if strings.Contains(err.Error(), \"unable to add CA to cert pool\") {\n        return fmt.Errorf(\"sslrootcert is not valid PEM; convert DER->PEM or fix the file: %w\", err)\n    }\n}","preventionTips":["Store CA certs in PEM (BEGIN CERTIFICATE) form only.","Validate the file with 'openssl x509 -in ca.pem -noout -text' during provisioning.","Use sslrootcert=system when the OS trust store is appropriate."],"tags":["tls","ssl","certificates","config","security"],"analyzedSha":"ec1a0befd22592cffffdeeb0a50311b506372f4c","analyzedAt":"2026-08-04T22:52:11.263Z","schemaVersion":2}