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

  1. Make the metric emit numeric values (Double, Long, or Integer) — convert Strings/booleans before returning from the IMetric.
  2. If values are non-numeric by design, use a different reducer (or write a custom IReducer) that supports the actual type.
  3. Inspect the message's input type name to find which metric emits the offending type and fix that metric's getValue return type.
  4. 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

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


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)