risingwavelabs/risingwave · error · anyhow::Error

bad ssl root cert error: {}

Error message

bad ssl root cert error: {}

What it means

When ssl_mode is verify-ca or verify-full, the connector builds an OpenSSL connector and loads the CA certificate file with `set_ca_file`. If that file cannot be read or parsed (missing path, bad permissions, not a PEM cert), it wraps the openssl error as 'bad ssl root cert error: ...'.

Source

Thrown at src/connector/src/connector_common/postgres.rs:636

                    tracing::warn!(error = %e.as_report(), "SSL connector error");
                    MaybeMakeTlsConnector::NoTls(NoTls)
                }
            }
        }
        SslMode::Required => {
            pg_config.ssl_mode(tokio_postgres::config::SslMode::Require);
            let mut builder = SslConnector::builder(SslMethod::tls())?;
            // disable certificate verification for `require`
            builder.set_verify(SslVerifyMode::NONE);
            MaybeMakeTlsConnector::Tls(MakeTlsConnector::new(builder.build()))
        }

        SslMode::VerifyCa | SslMode::VerifyFull => {
            pg_config.ssl_mode(tokio_postgres::config::SslMode::Require);
            let mut builder = SslConnector::builder(SslMethod::tls())?;
            if let Some(ssl_root_cert) = &config.ssl_root_cert {
                builder.set_ca_file(ssl_root_cert).map_err(|e| {
                    anyhow!(format!("bad ssl root cert error: {}", e.to_report_string()))
                })?;
            }
            let mut connector = MakeTlsConnector::new(builder.build());
            if !verify_hostname {
                connector.set_callback(|c, _| {
                    c.set_verify_hostname(false);
                    Ok(())
                });
            }
            MaybeMakeTlsConnector::Tls(connector)
        }
    };
    #[cfg(madsim)]
    let connector = NoTls;

    let (client, connection) = pg_config.connect(connector).await?;

    tokio::spawn(async move {

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Check that the `ssl_root_cert` path exists and is readable by the RisingWave process
  2. Ensure the file is PEM-encoded (`openssl x509 -in cert.pem -text -noout` to verify); convert with `openssl x509 -inform der -in cert.der -out cert.pem`
  3. Mount the CA cert into the container/pod and pass the container path
  4. Test the cert against the server with `psql 'sslmode=verify-ca sslrootcert=<path> ...'`

Example fix

-- before
ssl_root_cert = '/etc/ssl/certs/ca-bundle.crt.bak'
-- after (valid, readable PEM CA file)
ssl_root_cert = '/etc/ssl/certs/rds-ca.pem'
Defensive patterns

Strategy: validation

Validate before calling

use std::os::unix::fs::PermissionsExt;
fn check_ca_cert(path: &str) -> Result<(), String> {
    let meta = std::fs::metadata(path).map_err(|e| format!("ca cert unreadable: {e}"))?;
    if meta.permissions().mode() & 0o444 == 0 { return Err("ca cert not readable".into()); }
    // quick PEM sniff
    let head = std::fs::read_to_string(path).map_err(|e| format!("ca cert read: {e}"))?;
    if !head.contains("BEGIN CERTIFICATE") { return Err("ca cert is not PEM".into()); }
    Ok(())
}

Try / catch

match create_pg_client_from_properties(&props) {
    Err(e) if e.to_string().contains("bad ssl root cert") => {
        log::error!("CA cert misconfigured: {e}; check ssl_root_cert path/PEM encoding");
        Err(TlsConfigError::from(e))
    }
    other => other,
}

Prevention

When it happens

Trigger: Creating a tokio-postgres client (`create_pg_client` or `create_pg_client_from_properties`) with `ssl_mode = verify-ca`/`verify-full` and `ssl_root_cert` pointing to an unreadable/invalid file.

Common situations: Typo in the ssl_root_cert path; certificate file not mounted into the container; file is a DER/binary cert instead of PEM; file permissions deny the RisingWave process read access.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11). Data as JSON: /api/errors/628ecebab9222b41. Report an issue: GitHub.