apache/kafka · error · IllegalArgumentException

Unknown sensor {name}

Error message

Unknown sensor {name}

What it means

Thrown by PluginMetricsImpl.removeSensor when the supplied name is not in the handle's 'sensors' set — the sensor was either never added through this handle, was added through the raw Metrics object, or has already been removed. The handle enforces a strict add-before-remove contract: only sensors it created can be removed through it.

Source

Thrown at clients/src/main/java/org/apache/kafka/common/metrics/internals/PluginMetricsImpl.java:99

    @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)) {
            metrics.removeSensor(name);
            sensors.remove(name);
        } else {
            throw new IllegalArgumentException("Unknown sensor " + name);
        }
    }

    @Override
    public void close() throws IOException {
        closing = true;
        for (String sensor : sensors) {
            metrics.removeSensor(sensor);
        }
        for (MetricName metricName : metricNames) {
            metrics.removeMetric(metricName);
        }
    }
}

View on GitHub (pinned to c31c9215e1)

Solutions

  1. Only remove sensors you added via pluginMetrics.addSensor(name) on the same handle; track added names in a Set if you remove them selectively.
  2. If you created the sensor via metrics.sensor(name), remove it via metrics.removeSensor(name) instead.
  3. Guard removeSensor calls (or let PluginMetrics.close() do the cleanup) to avoid removing sensors you do not own.

Example fix

// before
Sensor s = metrics.sensor("x");                 // raw Metrics
...
pluginMetrics.removeSensor("x");                // Unknown sensor
// after
Sensor s = pluginMetrics.addSensor("x");        // PluginMetrics handle
...
pluginMetrics.removeSensor("x");                // ok
Defensive patterns

Strategy: validation

Validate before calling

// Track sensors you created; only remove what you own.
private final Set<String> registeredSensors = ConcurrentHashMap.newKeySet();
if (name == null || !registeredSensors.remove(name)) {
    return; // not created by this plugin
}
pluginMetrics.removeSensor(name);

Prevention

When it happens

Trigger: Calling pluginMetrics.removeSensor(name) for a sensor created via metrics.sensor(name) directly, created via a different PluginMetrics instance, or removed earlier. Also occurs when the name string differs in case or whitespace from the one passed to addSensor.

Common situations: Migrating a plugin to PluginMetrics but still creating some sensors with the legacy metrics.sensor() API; double-cleanup paths; plugins sharing state across instances where one instance tries to remove a sensor owned by another.

Related errors


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