{"id":"b681caa81d017172","repo":"apache/kafka","slug":"sensor-name-already-exists","errorCode":null,"errorMessage":"Sensor {name} already exists","messagePattern":"Sensor (.+?) already exists","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"clients/src/main/java/org/apache/kafka/common/metrics/internals/PluginMetricsImpl.java","lineNumber":85,"sourceCode":"        metricNames.add(metricName);\n    }\n\n    @Override\n    public void removeMetric(MetricName metricName) {\n        if (closing) throw new IllegalStateException(\"This PluginMetrics instance is closed\");\n        if (metricNames.contains(metricName)) {\n            metrics.removeMetric(metricName);\n            metricNames.remove(metricName);\n        } else {\n            throw new IllegalArgumentException(\"Unknown metric \" + metricName);\n        }\n    }\n\n    @Override\n    public Sensor addSensor(String name) {\n        if (closing) throw new IllegalStateException(\"This PluginMetrics instance is closed\");\n        if (sensors.contains(name)) {\n            throw new IllegalArgumentException(\"Sensor \" + name + \" already exists\");\n        }\n        Sensor sensor = metrics.sensor(name);\n        sensors.add(name);\n        return sensor;\n    }\n\n    @Override\n    public void removeSensor(String name) {\n        if (closing) throw new IllegalStateException(\"This PluginMetrics instance is closed\");\n        if (sensors.contains(name)) {\n            metrics.removeSensor(name);\n            sensors.remove(name);\n        } else {\n            throw new IllegalArgumentException(\"Unknown sensor \" + name);\n        }\n    }\n\n    @Override","sourceCodeStart":67,"sourceCodeEnd":103,"githubUrl":"https://github.com/apache/kafka/blob/c31c9215e131f8c17e79f8901b48c13ee6aa8e7a/clients/src/main/java/org/apache/kafka/common/metrics/internals/PluginMetricsImpl.java#L67-L103","documentation":"Thrown by PluginMetricsImpl.addSensor when a sensor with the given name was already added through this same PluginMetrics handle (the 'sensors' set contains the name). Each handle maintains its own namespace; within it, sensor names must be unique. The error guards against silently overwriting or double-registering a sensor which would confuse metric reporting and cleanup.","triggerScenarios":"Calling pluginMetrics.addSensor(\"foo\") twice on the same handle without an intervening removeSensor(\"foo\"). Common when a plugin is initialized multiple times (e.g. multiple Connect tasks in one worker sharing a plugin instance) or when sensor names are templated from a non-unique source.","commonSituations":"Connect converters/transformations instantiated per-task but sharing a PluginMetrics; plugins using a fixed sensor name like \"records\" across multiple parallel instances; re-init after a transient failure that does not run stop().","solutions":["Make sensor names unique per instance — include task id, partition, or a counter in the name (e.g. \"records-\" + taskId).","Cache the created Sensor in a field and reuse it; check sensor != null before calling addSensor.","Call removeSensor(name) before re-adding, or rely on PluginMetrics.close() to clear the namespace when the plugin instance is retired."],"exampleFix":"// before\nsensor = pluginMetrics.addSensor(\"records\"); // throws on 2nd task\n// after\nsensor = pluginMetrics.addSensor(\"records-\" + taskId);","handlingStrategy":"validation","validationCode":"// Maintain a Set<String> of sensor names you created.\nprivate final Set<String> registeredSensors = ConcurrentHashMap.newKeySet();\nif (name == null || name.isEmpty()) throw new IllegalArgumentException(\"sensor name required\");\nif (!registeredSensors.add(name)) {\n    return registeredSensorRefs.get(name); // already exists, reuse\n}\nSensor s = pluginMetrics.addSensor(name);\nregisteredSensorRefs.put(name, s);\nreturn s;","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Namespace sensor names with a stable prefix unique to your plugin instance (e.g. pluginId + '-' + purpose) to avoid collisions across plugins sharing the global Metrics registry.","Track created sensors in your own map and reuse them instead of recreating by the same name.","Never auto-generate sensor names from timestamps or random values that could collide; use deterministic, content-based names."],"tags":["metrics","plugin-lifecycle","naming","kafka-connect"],"analyzedSha":"c31c9215e131f8c17e79f8901b48c13ee6aa8e7a","analyzedAt":"2026-08-03T12:34:05.770Z","schemaVersion":2}