apache/kafka · error · IllegalArgumentException
Unknown metric {metricName}
Error message
Unknown metric {metricName} What it means
Thrown by PluginMetricsImpl.removeMetric when the supplied MetricName is not in the per-instance 'metricNames' set, i.e. the metric was never added through this PluginMetrics handle (or was already removed). The implementation is strict: you can only remove what you added via the same handle's addMetric. Attempting to remove a metric registered elsewhere, or removing the same name twice, is rejected.
Source
Thrown at clients/src/main/java/org/apache/kafka/common/metrics/internals/PluginMetricsImpl.java:77
@Override
public void addMetric(MetricName metricName, MetricValueProvider<?> metricValueProvider) {
if (closing) throw new IllegalStateException("This PluginMetrics instance is closed");
if (metricNames.contains(metricName)) {
throw new IllegalArgumentException("Metric " + metricName + " already exists");
}
metrics.addMetric(metricName, metricValueProvider);
metricNames.add(metricName);
}
@Override
public void removeMetric(MetricName metricName) {
if (closing) throw new IllegalStateException("This PluginMetrics instance is closed");
if (metricNames.contains(metricName)) {
metrics.removeMetric(metricName);
metricNames.remove(metricName);
} else {
throw new IllegalArgumentException("Unknown metric " + metricName);
}
}
@Override
public Sensor addSensor(String name) {
if (closing) throw new IllegalStateException("This PluginMetrics instance is closed");
if (sensors.contains(name)) {
throw new IllegalArgumentException("Sensor " + name + " already exists");
}
Sensor sensor = metrics.sensor(name);
sensors.add(name);
return sensor;
}
@Override
public void removeSensor(String name) {
if (closing) throw new IllegalStateException("This PluginMetrics instance is closed");
if (sensors.contains(name)) {View on GitHub (pinned to c31c9215e1)
Solutions
- Only remove metrics you added via the same pluginMetrics.addMetric(name, provider) call; track them in a field if needed.
- Verify the MetricName passed to removeMetric is exactly the object returned by pluginMetrics.metricName(...) — same group, name, and tags.
- If you registered the metric through the raw Metrics object instead of PluginMetrics, remove it through metrics.removeMetric(...) (or just let PluginMetrics.close() manage lifecycle).
Example fix
// before metrics.addMetric(name, provider); // registered on global Metrics ... pluginMetrics.removeMetric(name); // Unknown metric // after pluginMetrics.addMetric(name, provider); // registered on the handle ... pluginMetrics.removeMetric(name); // ok
Defensive patterns
Strategy: validation
Validate before calling
// Maintain a Set<MetricName> of metrics YOU registered with this PluginMetrics instance.
private final Set<MetricName> registered = ConcurrentHashMap.newKeySet();
// On addMetric: registered.add(name);
// Before removeMetric:
if (metricName == null || !registered.remove(metricName)) {
return; // not registered here, nothing to remove
}
pluginMetrics.removeMetric(metricName); Prevention
- Always track the MetricName objects you registered in your own collection rather than relying on the library to remember.
- Guard removeMetric with a contains-check on your own registry; never call removeMetric speculatively.
- Make cleanup idempotent: remove from your set first, and only call the library if removal succeeded.
- Remember MetricName equality is by value (name+group+tags), so the same logical metric removed twice will trigger this error.
When it happens
Trigger: Calling pluginMetrics.removeMetric(name) for a name that was added via metrics.addMetric directly, via a different PluginMetrics instance, or that has already been removed. Also triggered by passing a MetricName whose group/tags differ from the one returned by pluginMetrics.metricName(...) (MetricName equality includes group and tags).
Common situations: A plugin that registers metrics with the global Metrics object instead of the provided PluginMetrics handle and then tries to clean them up through the handle; double-cleanup in stop(); copy-paste of MetricName construction that yields a name equal by display string but not by the cached MetricName object's identity.
Related errors
- Unknown sensor {name}
- Not a measurable: {metricValueProviderClass}
- Sensor {name} already exists
- Must specify at least one metric name
- Partition {partition} was not included in the original reque
AI-assisted analysis of apache/kafka@c31c9215e1 (2026-08-03).
Data as JSON: /data/errors/a3cd4d01e9de1632.json.
Report an issue: GitHub.