zeroclaw-labs/zeroclaw · error

client_cert is set but client_key is missing (both are requi

Error message

client_cert is set but client_key is missing (both are required for mutual TLS)

What it means

Broker mutual TLS on the AMQP channel needs a certificate/key pair. The validator requires `client_cert` and `client_key` to be supplied together; setting only `client_cert` produces an incomplete identity that could never complete an mTLS handshake, so the config is rejected up front.

Source

Thrown at crates/zeroclaw-config/src/schema.rs:16619

    /// - at least one routing key is bound
    pub fn validate(&self) -> anyhow::Result<()> {
        let is_tls = self.amqp_url.starts_with("amqps://");
        let is_plain = self.amqp_url.starts_with("amqp://");

        if !is_tls && !is_plain {
            anyhow::bail!(
                "amqp_url must start with 'amqp://' or 'amqps://', got: {}",
                self.amqp_url
            );
        }

        if is_tls && self.ca_cert.is_none() {
            anyhow::bail!("amqps:// requires ca_cert to verify the broker");
        }

        match (self.client_cert.is_some(), self.client_key.is_some()) {
            (true, false) => {
                anyhow::bail!(
                    "client_cert is set but client_key is missing (both are required for mutual TLS)"
                )
            }
            (false, true) => {
                anyhow::bail!(
                    "client_key is set but client_cert is missing (both are required for mutual TLS)"
                )
            }
            _ => {}
        }

        if self.exchange.is_empty() {
            validation_bail!(RequiredFieldEmpty, "exchange", "exchange must not be empty");
        }

        if self.routing_keys.is_empty() {
            anyhow::bail!("at least one routing key must be configured");
        }

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Add the matching key: `client_key = "/etc/zeroclaw/client.key"`.
  2. Confirm both paths exist and the key matches the cert (`openssl x509 -noout -modulus` vs key modulus, or `openssl verify`).
  3. If mTLS is not needed, remove `client_cert` entirely (plain `amqps://` with just `ca_cert` is valid).

Example fix

# before
client_cert = "/etc/zeroclaw/client.pem"
# client_key missing

# after
client_cert = "/etc/zeroclaw/client.pem"
client_key = "/etc/zeroclaw/client.key"
Defensive patterns

Strategy: validation

Validate before calling

anyhow::ensure!(
    cfg.client_cert.is_some() == cfg.client_key.is_some(),
    "client_cert and client_key must be set together"
);

Type guard

fn mtls_pair_consistent(cert: &Option<PathBuf>, key: &Option<PathBuf>) -> bool {
    cert.is_some() == key.is_some()
}

Prevention

When it happens

Trigger: `client_cert = "/etc/zeroclaw/client.pem"` with no `client_key`; renaming or moving the key file and updating only the cert path; generating a new cert and forgetting to re-point the key.

Common situations: Setting up Fedora Messaging, which mandates client certificates; ops runbooks that rotate the cert but not the key path reference; copy-pasting half of an mTLS example block.

Understand the failure class

Related errors


AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23). Data as JSON: /api/errors/00ffb44efdbf72b0. Report an issue: GitHub.