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
- Check that the `ssl_root_cert` path exists and is readable by the RisingWave process
- 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`
- Mount the CA cert into the container/pod and pass the container path
- 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
- Always ship PEM-encoded CA certs and verify with `openssl x509`
- Mount certs at stable container paths and reference those paths in config
- Test the TLS config with `psql sslmode=verify-ca sslrootcert=...` before deploying
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.
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- parse ca file error: {0}
- Unable to setup an SSL connection
- Failed to read CA certificate
- Failed to parse CA certificate
- Failed to add CA certificate
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/628ecebab9222b41.
Report an issue: GitHub.