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
- Only remove sensors you added via pluginMetrics.addSensor(name) on the same handle; track added names in a Set if you remove them selectively.
- If you created the sensor via metrics.sensor(name), remove it via metrics.removeSensor(name) instead.
- 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
- Keep your own registry of created sensor names and only call removeSensor for names you successfully added.
- Make removeSensor idempotent: check your own set first.
- Never reuse a PluginMetrics instance to manage sensors created through the underlying Metrics object directly — they won't be tracked here.
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
- Unknown metric {metricName}
- 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/3af41aa39f626f0b.json.
Report an issue: GitHub.