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

  1. Ensure `cert_path` points to a PEM file with at least one `-----BEGIN CERTIFICATE-----` block.
  2. Check that cert and key paths are not swapped in the TLS config.
  3. 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

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.

Related errors


AI-assisted analysis of quickwit-oss/quickwit@a39730c5cd (2026-09-08). Data as JSON: /api/errors/54a8d2cd3d3588d7. Report an issue: GitHub.