nathanmarz/storm · error · RuntimeException
MeanReducer::reduce called with unsupported input type
Error message
MeanReducer::reduce called with unsupported input type `${input.getClass()}`. Supported types are Double, Long, Integer. What it means
MeanReducer averages incoming metric values but only understands Double, Long, and Integer inputs. If reduce receives any other object type (e.g. String, a custom Number, or a complex value emitted by a metric), it cannot add it to the running sum, so it throws with the offending class name in the message.
Solutions
- Make the metric emit numeric values (Double, Long, or Integer) — convert Strings/booleans before returning from the IMetric.
- If values are non-numeric by design, use a different reducer (or write a custom IReducer) that supports the actual type.
- Inspect the message's input type name to find which metric emits the offending type and fix that metric's getValue return type.
- If longs are wanted as double, have the metric emit Long/Double explicitly instead of custom Number subclasses.
Example fix
// before
public Object getValueAndReset() { return Long.toString(count); } // emits String
// after
public Object getValueAndReset() { return count; } // emits Long, accepted by MeanReducer Defensive patterns
Strategy: type-guard
Validate before calling
Object v = metric.getValueAndReset();
if (!(v instanceof Double || v instanceof Long || v instanceof Integer)) {
throw new IllegalStateException("MeanReducer metric must emit Double/Long/Integer, got " + v.getClass());
} Type guard
boolean isMeanReducerInput(Object v) {
return v instanceof Double || v instanceof Long || v instanceof Integer;
} Try / catch
try {
reducedStream.meanReduce(value);
} catch (RuntimeException e) {
if (e.getMessage() != null && e.getMessage().contains("MeanReducer::reduce")) {
// metric emitted a non-numeric type; fix the metric's getValueAndReset return type
} else throw e;
} Prevention
- Have every IMetric return a boxed numeric type (Long/Double) from getValueAndReset.
- Pair MeanReducer only with metrics documented as numeric.
- Write a unit test invoking MeanReducer.reduce with your metric's emitted value.
- Convert boolean/count-like metrics to Long before emitting.
When it happens
Trigger: Registering a MeanReducer as the reducer for a metric whose emitted values are not Double/Long/Integer — e.g. reducedMetrics registered with MeanReducer while the metric produces String or a custom object.
Common situations: Wiring MeanReducer to a metric that emits Strings or booleans; a custom IMetric implementation returning non-numeric objects; a metric's emitted type changed after a refactor while the reducer stayed the same.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- Each element of the list
- Field must be an Iterable of
- Could not instantiate a class listed in config under section
- A single worker should have 1 SystemBolt instance.
- Non-system tuples should never be sent to __system bolt.
AI-assisted analysis of nathanmarz/storm@cdb116e942 (2026-09-12).
Data as JSON: /api/errors/82dc5dce44a0c096.
Report an issue: GitHub.
Appendix: source
Thrown at storm-core/src/jvm/backtype/storm/metric/api/MeanReducer.java:41
public int count = 0;
public double sum = 0.0;
}
public class MeanReducer implements IReducer<MeanReducerState> {
public MeanReducerState init() {
return new MeanReducerState();
}
public MeanReducerState reduce(MeanReducerState acc, Object input) {
acc.count++;
if(input instanceof Double) {
acc.sum += (Double)input;
} else if(input instanceof Long) {
acc.sum += ((Long)input).doubleValue();
} else if(input instanceof Integer) {
acc.sum += ((Integer)input).doubleValue();
} else {
throw new RuntimeException(
"MeanReducer::reduce called with unsupported input type `" + input.getClass()
+ "`. Supported types are Double, Long, Integer.");
}
return acc;
}
public Object extractResult(MeanReducerState acc) {
if(acc.count > 0) {
return new Double(acc.sum / (double)acc.count);
} else {
return null;
}
}
}
View on GitHub (pinned to cdb116e942)