risingwavelabs/risingwave · error · PsqlError
Failed to parse client certificate
Error message
Failed to parse client certificate
What it means
After successfully reading the client certificate bytes, init_client_config parses them with CertificateDer::pem_slice_iter. If any PEM block in the file is not a valid certificate (bad base64, wrong PEM label, garbage, or a non-PEM file), the iterator yields Err and this StartupError is raised. The library aborts because a usable client certificate is required for the TLS client-auth handshake.
Source
Thrown at src/utils/pgwire/src/ldap_auth.rs:148
return Err(PsqlError::StartupError(
"Client certificate provided without private key".into(),
));
};
let client_cert_bytes = fs::read(cert).map_err(|e| {
PsqlError::StartupError(
anyhow!(e)
.context("Failed to read client certificate")
.into(),
)
})?;
let client_key_bytes = fs::read(key).map_err(|e| {
PsqlError::StartupError(anyhow!(e).context("Failed to read client key").into())
})?;
let client_certs = CertificateDer::pem_slice_iter(&client_cert_bytes)
.collect::<Result<Vec<_>, _>>()
.map_err(|e| {
PsqlError::StartupError(
anyhow!(e)
.context("Failed to parse client certificate")
.into(),
)
})?;
let client_private_key =
PrivateKeyDer::from_pem_slice(&client_key_bytes).map_err(|e| {
PsqlError::StartupError(anyhow!(e).context("Failed to parse client key").into())
})?;
tls_client_config
.with_client_auth_cert(client_certs, client_private_key)
.map_err(|err| {
PsqlError::StartupError(
anyhow!(err)
.context("Failed to set client certificate")
.into(),
)View on GitHub (pinned to 6469eb736d)
Solutions
- Check the file starts with -----BEGIN CERTIFICATE----- and ends with -----END CERTIFICATE-----
- Verify you are not pointing at the private key or CSR; use the issued client certificate
- Convert DER to PEM if needed: openssl x509 -inform der -in cert.der -out cert.pem
- Re-export the certificate cleanly (openssl x509 -in cert.pem -out clean.pem) to strip stray whitespace
Example fix
// before (config points at key file) client_cert = '/etc/rw/certs/client.key' // after client_cert = '/etc/rw/certs/client.crt' // PEM-encoded certificate
Defensive patterns
Strategy: validation
Validate before calling
fn is_pem_certificate(path: &str) -> bool {
std::fs::read_to_string(path).map(|s| {
s.contains("-----BEGIN CERTIFICATE-----") && s.contains("-----END CERTIFICATE-----")
}).unwrap_or(false)
}
// stronger check: openssl x509 -in cert.pem -noout >/dev/null Type guard
fn looks_like_cert_pem(bytes: &[u8]) -> bool {
let s = String::from_utf8_lossy(bytes);
s.contains("-----BEGIN CERTIFICATE-----")
} Try / catch
catch PsqlError::StartupError, downcast the inner anyhow chain to the rustls pki error and advise re-exporting the cert as PEM
Prevention
- Distribute certs in PEM format only; never DER for this config
- Keep cert and key in separate files and label filenames clearly (.crt vs .key)
- Verify with `openssl x509 -in cert.pem -noout` during deploy
- Avoid hand-editing PEM files; always copy whole files
When it happens
Trigger: CertificateDer::pem_slice_iter(&client_cert_bytes).collect::<Result<Vec<_>,_>>() returns Err — the file at `client_cert` contains malformed PEM or non-certificate PEM blocks
Common situations: Pointing `client_cert` at the private key file or at a combined bundle that includes a key/cSR; certificate file truncated during copy/paste; file contains DER (binary) instead of PEM; extra text before/after the BEGIN/END CERTIFICATE block.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Failed to parse CA certificate
- Failed to parse client key
- parse ca file error: {0}
- Failed to read CA certificate
- Failed to add CA certificate
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/0b9b63d95119560e.
Report an issue: GitHub.