{"record":{"id":"90c402d2f03b17bd","repo":"risingwavelabs/risingwave","slug":"failed-to-set-client-certificate","errorCode":null,"errorMessage":"Failed to set client certificate","messagePattern":"Failed to set client certificate","errorType":"exception","errorClass":"PsqlError","httpStatus":null,"severity":"error","filePath":"src/utils/pgwire/src/ldap_auth.rs","lineNumber":163,"sourceCode":"                .collect::<Result<Vec<_>, _>>()\n                .map_err(|e| {\n                    PsqlError::StartupError(\n                        anyhow!(e)\n                            .context(\"Failed to parse client certificate\")\n                            .into(),\n                    )\n                })?;\n\n            let client_private_key =\n                PrivateKeyDer::from_pem_slice(&client_key_bytes).map_err(|e| {\n                    PsqlError::StartupError(anyhow!(e).context(\"Failed to parse client key\").into())\n                })?;\n\n            tls_client_config\n                .with_client_auth_cert(client_certs, client_private_key)\n                .map_err(|err| {\n                    PsqlError::StartupError(\n                        anyhow!(err)\n                            .context(\"Failed to set client certificate\")\n                            .into(),\n                    )\n                })\n        } else {\n            Ok(tls_client_config.with_no_client_auth())\n        }\n    }\n}\n\n/// LDAP configuration extracted from HBA entry\n#[derive(Debug, Clone)]\npub struct LdapConfig {\n    /// LDAP server address\n    pub server: String,\n    /// LDAP bind DN template or search base\n    pub base_dn: Option<String>,\n    /// LDAP search filter template","sourceCodeStart":145,"sourceCodeEnd":181,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/utils/pgwire/src/ldap_auth.rs#L145-L181","documentation":"After both client certificate and key parse successfully, rustls' ClientConfig::with_client_auth_cert(cert_chain, key_der) is called; it fails if the private key does not match the first certificate in the chain (or the key type is otherwise rejected). RisingWave wraps that as this StartupError: the mTLS identity is internally inconsistent.","triggerScenarios":"tls_client_config.with_client_auth_cert(client_certs, client_private_key) returns Err — key/cert mismatch or invalid cert chain","commonSituations":"Mixing cert and key from different generations (regenerated the key but reused the old cert); cert chain ordering where leaf is not first; using a CA cert as the client cert with an unrelated key.","solutions":["Verify cert and key match: compare modulus/public key hash (openssl x509 -noout -modem vs openssl rsa -noout -modulus)","Regenerate cert+key as a pair and update both config paths","Ensure the leaf client certificate is the first entry in the cert file, followed by intermediates","If mTLS is not required by the LDAP server, remove the client cert/key config to fall into the with_no_client_auth branch"],"exampleFix":"// before: mismatched pair\nclient_cert = '/etc/rw/certs/old.crt'   // key regenerated since\n// after\nopenssl req -x509 -newkey rsa:2048 -nodes -keyout client.key -out client.crt ...\nclient_cert = '/etc/rw/certs/client.crt'\nclient_key  = '/etc/rw/certs/client.key'","handlingStrategy":"validation","validationCode":"// deploy-time check that cert and key match\n# openssl x509 -noout -pubkey -in client.crt | sha256sum\n# openssl pkey -pubout -in client.key | sha256sum\n# hashes must be equal before configuring mTLS","typeGuard":null,"tryCatchPattern":"catch PsqlError::StartupError for 'Failed to set client certificate' and surface an explicit 'cert/key mismatch — regenerate as a pair' message","preventionTips":["Always generate and rotate cert+key together and deploy atomically","Script the pubkey-hash comparison of cert vs key in CI/deploy","Put the leaf certificate first in any combined chain file","Only enable client cert config when the LDAP server actually requires mTLS"],"tags":["ldap","tls","mtls","certificate-mismatch","startup"],"backgroundTag":"invalid-config-value","analyzedSha":"6469eb736d691e8e9b8a419a57edd6429ca77417","analyzedAt":"2026-09-11T21:06:21.487Z","contentChangedAt":"2026-09-11T21:06:21.487Z","schemaVersion":2},"datasetVersion":"2026-09-14T21:17:11.552Z"}