quickwit-oss/quickwit · error
no certificate found in `{cert_path}`
Error message
no certificate found in `{cert_path}` What it means
When building a rustls CertifiedKey for TLS, `load_certified_key` parses the certificate chain file via `load_certs`. If the PEM parses successfully but yields zero certificates, it bails. This typically means the file exists but contains no cert blocks (empty file, key-only file, or wrong content).
Source
Thrown at quickwit/quickwit-transport/src/tls.rs:92
rustls_pemfile::certs(&mut reader).collect()
}
/// Loads a single private key (PEM) from `filename`.
fn load_private_key(filename: &str) -> io::Result<PrivateKeyDer<'static>> {
let keyfile = fs::File::open(filename)
.map_err(|error| io_error(format!("failed to open {filename}: {error}")))?;
let mut reader = io::BufReader::new(keyfile);
let key_opt = rustls_pemfile::private_key(&mut reader)?;
key_opt.ok_or_else(|| io_error(format!("no private key found in {filename}")))
}
/// Reads the certificate chain and private key from disk and assembles a [`CertifiedKey`] using the
/// process-wide default crypto provider (ring, see
/// `quickwit_cli::install_default_crypto_ring_provider`).
fn load_certified_key(cert_path: &str, key_path: &str) -> anyhow::Result<CertifiedKey> {
let certs = load_certs(cert_path)?;
if certs.is_empty() {
anyhow::bail!("no certificate found in `{cert_path}`");
}
let key = load_private_key(key_path)?;
let crypto_provider = rustls::crypto::CryptoProvider::get_default()
.context("no default rustls crypto provider is installed")?;
let signing_key = crypto_provider
.key_provider
.load_private_key(key)
.with_context(|| format!("private key in `{key_path}` is not usable"))?;
let certified_key = CertifiedKey::new(certs, signing_key);
// Guard against swapping in a mismatched cert/key pair, e.g. if the reload task reads the two
// files mid-rotation. A definite mismatch is fatal; an inconclusive result (key type that
// cannot expose its public key) is tolerated since we cannot do better.
match certified_key.keys_match() {
Ok(()) => {}
Err(rustls::Error::InconsistentKeys(rustls::InconsistentKeys::KeyMismatch)) => {
anyhow::bail!(
"private key in `{key_path}` does not match certificate in `{cert_path}`"
);View on GitHub (pinned to a39730c5cd)
Solutions
- Ensure `cert_path` points to a PEM file with at least one `-----BEGIN CERTIFICATE-----` block.
- Check that cert and key paths are not swapped in the TLS config.
- Fix the deployment/rotation script so the cert file is never empty (write to temp file + atomic rename).
Example fix
// before cert_path: "/etc/quickwit/tls/key.pem" // actually the key key_path: "/etc/quickwit/tls/cert.pem" // after cert_path: "/etc/quickwit/tls/cert.pem" key_path: "/etc/quickwit/tls/key.pem"
Defensive patterns
Strategy: validation
Validate before calling
let certs = load_certs(&cert_path)?;
if certs.is_empty() {
return Err(anyhow!("pre-check: {} has no certificates", cert_path));
} Try / catch
if let Err(e) = tls_config.load() {
if e.to_string().contains("no certificate found") {
eprintln!("check cert_path content and cert/key ordering: {e}");
}
return Err(e);
} Prevention
- Never write empty cert files during rotation; use atomic rename.
- Double-check cert vs key path ordering in configs.
- Validate PEM contents in deployment scripts (grep for BEGIN CERTIFICATE).
When it happens
Trigger: Configuring TLS with a `cert_path` pointing to an empty file, a file containing only a private key, or a file whose PEM blocks are not parseable certificates.
Common situations: Swapping cert and key paths in config; certificate rotation scripts writing an empty file temporarily; downloading a chain with no PEM content; mount failures leaving placeholder files.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- private key in `{key_path}` does not match certificate in `{
- TLS CA certificate path (`tls.ca_path`) is not set; it is re
- no CA certificate found in `{ca_path}`
- `tls.cert_poll_interval` must be greater than zero, got `{}`
- registering a signal handler for SIGHUP should not fail
AI-assisted analysis of quickwit-oss/quickwit@a39730c5cd (2026-09-08).
Data as JSON: /api/errors/54a8d2cd3d3588d7.
Report an issue: GitHub.