{"record":{"id":"fbada46b30fedf9b","repo":"t8y2/dbx","slug":"client-certificate-and-key-must-be-provided-togeth","errorCode":null,"errorMessage":"Client certificate and key must be provided together","messagePattern":"Client certificate and key must be provided together","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"agents/drivers/mongodb/src/main/java/com/dbx/agent/mongodb/MongoAgent.java","lineNumber":118,"sourceCode":"        return json == null || json.isBlank() ? null : Document.parse(json);\n    }\n\n    static MongoClientSettings.Builder configureBuilder(JsonObject connObj) {\n        String host = connObj.has(\"host\") ? connObj.get(\"host\").getAsString() : \"127.0.0.1\";\n        int port = connObj.has(\"port\") ? connObj.get(\"port\").getAsInt() : 27017;\n        String username = coalesce(stringOrNull(connObj, \"username\"));\n        String password = coalesce(stringOrNull(connObj, \"password\"));\n        String authDatabase = authenticationDatabase(connObj);\n        String connectionString = stringOrNull(connObj, \"connection_string\");\n        boolean ssl = connObj.has(\"ssl\") && !connObj.get(\"ssl\").isJsonNull() && connObj.get(\"ssl\").getAsBoolean();\n        String caCertPath = stringOrNull(connObj, \"ca_cert_path\");\n        String clientCertPath = firstNonBlank(\n            stringOrNull(connObj, \"client_cert_path\"), stringOrNull(connObj, \"cert_path\"));\n        String clientKeyPath = firstNonBlank(\n            stringOrNull(connObj, \"client_key_path\"), stringOrNull(connObj, \"key_path\"));\n\n        if ((clientCertPath == null) != (clientKeyPath == null)) {\n            throw new IllegalArgumentException(\"Client certificate and key must be provided together\");\n        }\n\n        MongoClientSettings.Builder builder = MongoClientSettings.builder();\n        if (connectionString != null && !connectionString.isBlank()) {\n            builder.applyConnectionString(new ConnectionString(connectionString));\n        } else {\n            builder.applyToClusterSettings(\n                settings -> settings.hosts(Collections.singletonList(new ServerAddress(host, port))));\n            if (!username.isBlank()) {\n                builder.credential(MongoCredential.createCredential(username, authDatabase, password.toCharArray()));\n            }\n        }\n\n        if (ssl) {\n            applyTlsSettings(builder, caCertPath, clientCertPath, clientKeyPath);\n        }\n\n        return builder;","sourceCodeStart":100,"sourceCodeEnd":136,"githubUrl":"https://github.com/t8y2/dbx/blob/c0390bff16418b651f4728520d99adf8ce48829a/agents/drivers/mongodb/src/main/java/com/dbx/agent/mongodb/MongoAgent.java#L100-L136","documentation":"MongoAgent's configureBuilder validates TLS client authentication options: a client certificate path without its private key path (or vice versa) is invalid, since mTLS requires both. The XOR check on the resolved cert/key paths throws IllegalArgumentException immediately during connection setup.","triggerScenarios":"Passing client_cert_path/cert_path without client_key_path/key_path (or the reverse) in the MongoDB connection object; a blank/whitespace value making one path null while the other is set.","commonSituations":"Copy-pasting a config sample with only the cert; secrets manager mounting the cert but not the key (wrong file permissions); renaming keys in config (cert_path vs client_cert_path) so only one resolves via firstNonBlank; mTLS setups where the key is embedded elsewhere.","solutions":["Provide both the client certificate and its private key paths in the connection object.","Check which config key names you used — client_cert_path/cert_path and client_key_path/key_path are both accepted, but both sides must resolve.","Verify the key file actually exists and is mounted/readable in your environment.","If the key is embedded in a combined PEM, point both options at it or use the connection string's tlsCertificateKeyFile instead."],"exampleFix":"// before\n{\"connection\": {\"connection_string\": \"mongodb://host\", \"client_cert_path\": \"/etc/ssl/client.pem\"}}\n// after\n{\"connection\": {\"connection_string\": \"mongodb://host\", \"client_cert_path\": \"/etc/ssl/client.pem\", \"client_key_path\": \"/etc/ssl/client-key.pem\"}}","handlingStrategy":"validation","validationCode":"function validateMtlsPair(conn) {\n  const cert = conn.client_cert_path ?? conn.cert_path;\n  const key = conn.client_key_path ?? conn.key_path;\n  if ((cert != null) !== (key != null)) {\n    throw new Error('Client certificate and key must be provided together');\n  }\n  return true;\n}","typeGuard":"function hasCompleteMtlsConfig(conn) {\n  const cert = conn?.client_cert_path ?? conn?.cert_path;\n  const key = conn?.client_key_path ?? conn?.key_path;\n  return (cert == null) === (key == null);\n}","tryCatchPattern":"try {\n  agent.connect(mongoParams);\n} catch (IllegalArgumentException e) {\n  if (e.getMessage().contains(\"certificate and key must be provided together\")) {\n    // fix the connection object to include both client_cert_path and client_key_path, then retry\n  } else { throw e; }\n}","preventionTips":["Always set client cert and key options as a pair in config templates.","Validate config (both or neither of cert/key present) before calling connect.","Check secret mounts: both files must exist and be readable at the given paths.","When key names differ across environments, confirm firstNonBlank-compatible keys resolve on both sides."],"tags":["mongodb","tls","mtls","config-validation"],"backgroundTag":"tls-client-cert-config-invalid","analyzedSha":"c0390bff16418b651f4728520d99adf8ce48829a","analyzedAt":"2026-09-05T23:05:10.900Z","contentChangedAt":"2026-09-05T23:05:10.900Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}