{"record":{"id":"14858e434db15251","repo":"elastic/elasticsearch","slug":"telemetry-logs-ssl-certificate-and-telemetry-logs","errorCode":null,"errorMessage":"telemetry.logs.ssl.certificate and telemetry.logs.ssl.key must both be set or both be unset","messagePattern":"telemetry\\.logs\\.ssl\\.certificate and telemetry\\.logs\\.ssl\\.key must both be set or both be unset","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"modules/apm/src/main/java/org/elasticsearch/telemetry/apm/internal/export/otelsdk/OtelSdkSettings.java","lineNumber":300,"sourceCode":"    );\n\n    /**\n     * Path to the PEM-encoded client certificate for mTLS authentication to the otel-delivery-gateway.\n     * Must be set together with {@link #TELEMETRY_LOGS_SSL_KEY}.\n     * Path is resolved relative to the Elasticsearch config directory when not absolute.\n     */\n    public static final Setting<String> TELEMETRY_LOGS_SSL_CERTIFICATE = Setting.simpleString(\n        \"telemetry.logs.ssl.certificate\",\n        \"\",\n        new Setting.Validator<>() {\n            @Override\n            public void validate(String value) {}\n\n            @Override\n            public void validate(String value, Map<Setting<?>, Object> settings) {\n                String key = (String) settings.get(TELEMETRY_LOGS_SSL_KEY);\n                if (value.isEmpty() != key.isEmpty()) {\n                    throw new IllegalArgumentException(\n                        TELEMETRY_LOGS_SSL_CERTIFICATE.getKey()\n                            + \" and \"\n                            + TELEMETRY_LOGS_SSL_KEY.getKey()\n                            + \" must both be set or both be unset\"\n                    );\n                }\n            }\n\n            @Override\n            public Iterator<Setting<?>> settings() {\n                return List.<Setting<?>>of(TELEMETRY_LOGS_SSL_KEY).iterator();\n            }\n        },\n        NodeScope\n    );\n\n    /**\n     * Path to the PEM-encoded private key for the client certificate ({@link #TELEMETRY_LOGS_SSL_CERTIFICATE}).","sourceCodeStart":282,"sourceCodeEnd":318,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/modules/apm/src/main/java/org/elasticsearch/telemetry/apm/internal/export/otelsdk/OtelSdkSettings.java#L282-L318","documentation":"telemetry.logs.ssl.certificate is a simpleString with a paired validator: it checks that telemetry.logs.ssl.key is in the same emptiness state. If exactly one of {certificate, key} is set (cert present + key absent, or vice-versa) the validator throws IllegalArgumentException. This is the cert-side of the pair; an identical check is performed from the key setting.","triggerScenarios":"Configuring telemetry.logs.ssl.certificate without telemetry.logs.ssl.key, or vice-versa, in elasticsearch.yml or via cluster update settings.","commonSituations":"Uploading only the public cert during mTLS setup; rotating one half of the pair; copy-paste that dropped the key line.","solutions":["Provide both telemetry.logs.ssl.certificate and telemetry.logs.ssl.key, OR omit both (to disable mTLS client auth).","When rotating, update both keys atomically in a single cluster update-settings call.","Verify paths point to readable PEM files for both."],"exampleFix":"// before\ntelemetry.logs.ssl.certificate: certs/client.crt\n// missing key\n// after\ntelemetry.logs.ssl.certificate: certs/client.crt\ntelemetry.logs.ssl.key: certs/client.key","handlingStrategy":"validation","validationCode":"// cert and key must be both-set or both-unset\nstatic String check(String cert, String key) {\n  if (cert.isEmpty() != key.isEmpty())\n    return \"telemetry.logs.ssl.certificate and telemetry.logs.ssl.key must both be set or both be unset\";\n  return null;\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always configure cert and key as a pair.","When rotating, update both in a single cluster update-settings request."],"tags":["apm","telemetry","tls","ssl","configuration","validation"],"backgroundTag":null,"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}