apache/hadoop · error · MetricsException
Unsupported metric field {} of type {}
Error message
Unsupported metric field {} of type {} What it means
When a metrics source class is initialized, Hadoop metrics2's MutableMetricsFactory reflectively scans every field annotated with @Metric and instantiates a Mutable metric based on the field's exact declared type. Only MutableCounterInt, MutableCounterLong, MutableGaugeInt, MutableGaugeLong, MutableGaugeFloat, MutableRate, MutableRates, MutableRatesWithAggregation, MutableStat, MutableRollingAverages and MutableQuantiles are recognized (matching is exact Class equality). Any other declared type falls through to this MetricsException, naming the offending field and its type, and fails source registration at startup.
Source
Thrown at hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/metrics2/lib/MutableMetricsFactory.java:90
return new MutableRates(registry);
}
if (cls == MutableRatesWithAggregation.class) {
return registry.newRatesWithAggregation(info.name());
}
if (cls == MutableStat.class) {
return registry.newStat(info.name(), info.description(),
annotation.sampleName(), annotation.valueName(),
annotation.always());
}
if (cls == MutableRollingAverages.class) {
return registry.newMutableRollingAverages(info.name(),
annotation.valueName());
}
if (cls == MutableQuantiles.class) {
return registry.newQuantiles(info.name(), annotation.about(),
annotation.sampleName(), annotation.valueName(), annotation.interval());
}
throw new MetricsException("Unsupported metric field "+ field.getName() +
" of type "+ field.getType().getName());
}
MutableMetric newForMethod(Object source, Method method, Metric annotation,
MetricsRegistry registry) {
if (LOG.isDebugEnabled()) {
LOG.debug("method "+ method +" with annotation "+ annotation);
}
MetricsInfo info = getInfo(annotation, method);
MutableMetric metric = newForMethod(source, method, annotation);
metric = metric != null ? metric :
new MethodMetric(source, method, info, annotation.type());
registry.add(info.name(), metric);
return metric;
}
/**
* Override to handle custom mutable metrics for fieldsView on GitHub (pinned to 2add963021)
Solutions
- Change the field's declared type to a supported class, e.g. MutableCounterLong, MutableGaugeLong, MutableStat, MutableRate, MutableQuantiles or MutableRollingAverages
- For a genuinely custom metric type, override MutableMetricsFactory#newForField(Field, Metric) (the hook exists exactly for custom mutable metrics) instead of relying on the type map
- If the registry pattern is not needed, implement MetricsSource directly and emit MetricsRecords without @Metric fields
Example fix
// before
@Metrics(about="Job metrics", context="myjob")
public class MyMetrics {
@Metric MutableMetric requests; // Unsupported metric field requests of type ...
}
// after
@Metrics(about="Job metrics", context="myjob")
public class MyMetrics {
@Metric MutableCounterLong requests;
} Defensive patterns
Strategy: type-guard
Validate before calling
Set<Class<?>> SUPPORTED = new HashSet<>(Arrays.asList(
MutableCounterInt.class, MutableCounterLong.class,
MutableGaugeInt.class, MutableGaugeLong.class, MutableGaugeFloat.class,
MutableRate.class, MutableRates.class, MutableRatesWithAggregation.class,
MutableStat.class, MutableRollingAverages.class, MutableQuantiles.class));
for (Field f : MyMetrics.class.getDeclaredFields()) {
if (f.isAnnotationPresent(Metric.class) && !SUPPORTED.contains(f.getType())) {
throw new IllegalStateException("Bad @Metric field " + f.getName()
+ " of type " + f.getType().getName());
}
} Type guard
static boolean isSupportedMetricField(Field f) {
if (!f.isAnnotationPresent(Metric.class)) return true;
Class<?> t = f.getType();
return t == MutableCounterInt.class || t == MutableCounterLong.class
|| t == MutableGaugeInt.class || t == MutableGaugeLong.class
|| t == MutableGaugeFloat.class || t == MutableRate.class
|| t == MutableRates.class || t == MutableRatesWithAggregation.class
|| t == MutableStat.class || t == MutableRollingAverages.class
|| t == MutableQuantiles.class;
} Try / catch
try {
metricsSystem.register("myjob", "My job metrics", new MyMetrics());
} catch (MetricsException e) {
// message names the exact unsupported field and its type
throw new IllegalStateException("Metrics source registration failed: " + e.getMessage(), e);
} Prevention
- Always declare @Metric fields with a concrete supported Mutable* class, never MutableMetric or a custom subclass
- Import Mutable types only from org.apache.hadoop.hadoop.metrics2.lib — same-named classes elsewhere fail the exact Class comparison
- Add a unit test that instantiates every @Metrics-annotated class so unsupported fields fail in CI, not at daemon startup
When it happens
Trigger: Declaring @Metric on a field whose type is not in the supported list: @Metric MutableMetric requests; @Metric int counter; or @Metric on a custom MutableMetric subclass (exact class comparison means subclasses do NOT match). Thrown from newForField during MetricsSystem.register() or annotation-driven init of a @Metrics class.
Common situations: Writing a custom MetricsSource and declaring the interface type instead of a concrete class; porting code between Hadoop versions where a Mutable* type (e.g. MutableQuantiles, MutableRollingAverages, MutableRatesWithAggregation) does not exist so a hand-written stand-in is used; importing a same-named class from another package so the Class identity check fails.
Related errors
- Unsupported counter type: {}
- Unsupported gauge type: {}
- Unsupported tag type: {}
- Error creating plugin: {}
- Unexpected metrics type {} for {}
AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22).
Data as JSON: /api/errors/7d13d36d853bd7ac.
Report an issue: GitHub.