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

  1. Only remove metrics you added via the same pluginMetrics.addMetric(name, provider) call; track them in a field if needed.
  2. Verify the MetricName passed to removeMetric is exactly the object returned by pluginMetrics.metricName(...) — same group, name, and tags.
  3. 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

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


AI-assisted analysis of apache/kafka@c31c9215e1 (2026-08-03). Data as JSON: /data/errors/a3cd4d01e9de1632.json. Report an issue: GitHub.