apache/hadoop · error · MetricsException
Unsupported counter type: {}
Error message
Unsupported counter type: {} What it means
MethodMetric.newCounter builds the implementation for an @Metric-annotated method with type COUNTER; only int/Integer and long/Long return types are supported. Any other return type falls through to MetricsException('Unsupported counter type: <class name>').
Source
Thrown at hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/metrics2/lib/MethodMetric.java:86
return null;
}
}
MutableMetric newCounter(final Class<?> type) {
if (isInt(type) || isLong(type)) {
return new MutableMetric() {
@Override public void snapshot(MetricsRecordBuilder rb, boolean all) {
try {
Object ret = method.invoke(obj, (Object[])null);
if (isInt(type)) rb.addCounter(info, ((Integer) ret).intValue());
else rb.addCounter(info, ((Long) ret).longValue());
} catch (Exception ex) {
LOG.error("Error invoking method "+ method.getName(), ex);
}
}
};
}
throw new MetricsException("Unsupported counter type: "+ type.getName());
}
static boolean isInt(Class<?> type) {
boolean ret = type == Integer.TYPE || type == Integer.class;
return ret;
}
static boolean isLong(Class<?> type) {
return type == Long.TYPE || type == Long.class;
}
static boolean isFloat(Class<?> type) {
return type == Float.TYPE || type == Float.class;
}
static boolean isDouble(Class<?> type) {
return type == Double.TYPE || type == Double.class;
}View on GitHub (pinned to 2add963021)
Solutions
- Change the method's return type to int or long
- If the value is genuinely fractional, keep the metric a GAUGE instead of COUNTER
- Move the counter to an annotated MutableCounterLong field instead of a method
Example fix
// before
@Metric(type=Type.COUNTER)
public double filesRead() { return total; }
// after
@Metric(type=Type.COUNTER)
public long filesRead() { return total; } Defensive patterns
Strategy: type-guard
Validate before calling
for (Method m : cls.getDeclaredMethods()) {
Metric ann = m.getAnnotation(Metric.class);
if (ann != null && ann.type() == Type.COUNTER && !isCounterType(m.getReturnType())) {
throw new IllegalStateException("@Metric COUNTER on non-int/long method: " + m);
}
} Type guard
static boolean isCounterType(Class<?> t) {
return t == int.class || t == Integer.class
|| t == long.class || t == Long.class;
} Try / catch
try {
new MetricsSourceBuilder(obj, "MyMetrics").build();
} catch (MetricsException e) {
// check annotated method return types against isCounterType before build to avoid this
throw e;
} Prevention
- Keep counter methods int/long only; convert doubles before returning
- Add a startup unit test that scans @Metric COUNTER methods with isCounterType
- Prefer @Metric on MutableCounterLong fields over methods for counters
When it happens
Trigger: @Metric(type=Type.COUNTER) on a method returning double, float, String, Boolean, or any type other than int/Integer/long/Long — MetricsSourceBuilder scans methods and delegates each to MethodMetric.
Common situations: Copy-pasting a gauge method (double) and flipping the annotation to COUNTER; refactoring a counter method's return type without updating the annotation; annotated methods returning boxed or custom types.
Related errors
- Unsupported gauge type: {}
- Unsupported tag type: {}
- Error setting field {} annotated with {}
- Unsupported metric field {} of type {}
- Error creating plugin: {}
AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22).
Data as JSON: /api/errors/82fd807cf097e5bc.
Report an issue: GitHub.