apache/kafka · error · IllegalArgumentException
A metric named '{metricName}' already exists, can't register
Error message
A metric named '{metricName}' already exists, can't register another one. What it means
Thrown by Metrics.addMetric when a KafkaMetric with an equal MetricName is already registered in the same Metrics instance. MetricName equality is determined by group, name, and tags, so a second addMetric call with the same triple collides. Kafka treats metric identity as unique per Metrics registry because reporters (JMX, etc.) key off the MetricName and duplicate registration would produce ambiguous values.
Source
Thrown at clients/src/main/java/org/apache/kafka/common/metrics/Metrics.java:520
/**
* Add a metric to monitor an object that implements MetricValueProvider. This metric won't be associated with any
* sensor. This is a way to expose existing values as metrics. User is expected to add any additional
* synchronization to update and access metric values, if required.
*
* @param metricName The name of the metric
* @param metricValueProvider The metric value provider associated with this metric
* @throws IllegalArgumentException if a metric with same name already exists.
*/
public void addMetric(MetricName metricName, MetricConfig config, MetricValueProvider<?> metricValueProvider) {
KafkaMetric m = new KafkaMetric(new Object(),
Objects.requireNonNull(metricName),
Objects.requireNonNull(metricValueProvider),
config == null ? this.config : config,
time);
KafkaMetric existingMetric = registerMetric(m);
if (existingMetric != null) {
throw new IllegalArgumentException("A metric named '" + metricName + "' already exists, can't register another one.");
}
}
/**
* Add a metric to monitor an object that implements MetricValueProvider. This metric won't be associated with any
* sensor. This is a way to expose existing values as metrics. User is expected to add any additional
* synchronization to update and access metric values, if required.
*
* @param metricName The name of the metric
* @param metricValueProvider The metric value provider associated with this metric
*/
public void addMetric(MetricName metricName, MetricValueProvider<?> metricValueProvider) {
addMetric(metricName, null, metricValueProvider);
}
/**
* Create or get an existing metric to monitor an object that implements MetricValueProvider.
* This metric won't be associated with any sensor. This is a way to expose existing values as metrics.View on GitHub (pinned to c31c9215e1)
Solutions
- Use Metrics.addMetricIfAbsent(name, config, provider) if idempotent registration is desired.
- Before adding, call Metrics.metric(name) or Metrics.metrics().get(name); if non-null, removeMetric(name) or skip.
- Ensure the MetricName tags actually distinguish logically separate metrics (e.g. include node-id, topic, partition).
- Tear down metrics in close()/close() of the owning component so re-init does not collide.
Example fix
// before: metrics.addMetric(name, provider); // throws if already registered // after: metrics.addMetricIfAbsent(name, null, provider);
Defensive patterns
Strategy: validation
Validate before calling
// Check the live metrics map before registering a new one.
MetricName name = metrics.metricName("rate", "grp", "desc", tags);
if (metrics.metrics().containsKey(name)) {
// already registered; reuse or skip instead of re-adding.
return metrics.metrics().get(name);
}
metrics.addMetric(name, provider); Type guard
// Narrow to not-already-registered before calling addMetric.
boolean isUnregistered(Metrics metrics, MetricName name) {
return metrics != null && name != null && !metrics.metrics().containsKey(name);
} Try / catch
try {
metrics.addMetric(metricName, provider);
} catch (IllegalArgumentException e) {
// collision: log and reuse the existing metric from metrics.metrics().get(metricName)
} Prevention
- Always check metrics.metrics().containsKey(name) before addMetric in plugin/library code.
- Prefer addMetricAndMetricName (get-or-create) over addMetric when you only need a reference.
- Derive MetricName from a stable template to avoid accidental duplicates from tag drift.
- Tear down metrics on close before re-registering to avoid stale-name collisions in tests.
When it happens
Trigger: Code calls Metrics.addMetric(name, provider) twice with the same MetricName, or adds a metric whose name collides with one already registered by addSensor/addMetric earlier. registerMetric returns the existing metric and addMetric at line 519-520 throws IllegalArgumentException naming the MetricName.
Common situations: Plugin code that re-initialises metrics on reconnect without first removing the old ones. Multi-tenant setups where tags intended to differentiate metrics are missing or constant. Frameworks (Connect, Streams) wrapping the producer and re-adding metrics on task recreation. Calling addMetric inside a loop with reused tag maps.
Related errors
- Metric {metricName} already exists
- A metric named '{metricName}' already exists, can't register
- Telemetry is not enabled. Set config `enable.metrics.push` t
- Error creating mbean attribute for metricName :{metricName}
- Error unregistering mbean
AI-assisted analysis of apache/kafka@c31c9215e1 (2026-08-03).
Data as JSON: /data/errors/f3de771d7f42b4fe.json.
Report an issue: GitHub.