nathanmarz/storm · error · IllegalArgumentException

Combiner aggs only take a single field as input. Got this…

Error message

Combiner aggs only take a single field as input. Got this instead: 

What it means

MapCombinerAggStateUpdater applies a CombinerAggregator over grouped state, and CombinerAggregators by contract reduce exactly one input field per tuple. The constructor validates inputFields and throws IllegalArgumentException if more or fewer than one field is supplied.

Solutions

  1. Pass exactly one field: persistentAggregate(state, new Sum(new Fields("value")), new Fields("sum"))
  2. If multiple inputs are needed, combine them first with each() into a single field, or use a ReducerAggregator/Aggregator instead
  3. Ensure the value fields selector excludes group fields

Example fix

// before
.persistentAggregate(state, new Sum(), new Fields("a", "b"), new Fields("sum"))
// after
.persistentAggregate(state, new Sum(new Fields("a")), new Fields("sum"))
Defensive patterns

Strategy: validation

Validate before calling

if (inputFields.size() != 1) {
  throw new IllegalArgumentException("CombinerAggregator requires exactly one input field, got: " + inputFields);
}

Try / catch

try {
  stream.persistentAggregate(stateFactory, combinerAgg, valueFields, new Fields("out"));
} catch (IllegalArgumentException e) {
  LOG.error("persistentAggregate field count invalid: " + e.getMessage());
}

Prevention

When it happens

Trigger: Calling persistentAggregate with a CombinerAggregator (e.g. Count(), Sum(new Fields("x"))) where the value Fields has size != 1, e.g. new Fields("a","b") or empty fields.

Common situations: Trying to aggregate multiple columns with a combiner agg; passing zero-arg Fields by mistake; converting a ReducerAggregator pipeline to CombinerAggregator without trimming fields.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of nathanmarz/storm@cdb116e942 (2026-09-12). Data as JSON: /api/errors/1e209eba2c686ef1. Report an issue: GitHub.

Appendix: source

Thrown at storm-core/src/jvm/storm/trident/state/map/MapCombinerAggStateUpdater.java:49

import storm.trident.tuple.ComboList;
import storm.trident.tuple.TridentTuple;
import storm.trident.tuple.TridentTupleView.ProjectionFactory;

public class MapCombinerAggStateUpdater implements StateUpdater<MapState> {
    CombinerAggregator _agg;
    Fields _groupFields;
    Fields _inputFields;
    ProjectionFactory _groupFactory;
    ProjectionFactory _inputFactory;
    ComboList.Factory _factory;
    
    
    public MapCombinerAggStateUpdater(CombinerAggregator agg, Fields groupFields, Fields inputFields) {
        _agg = agg;
        _groupFields = groupFields;
        _inputFields = inputFields;
        if(inputFields.size()!=1) {
            throw new IllegalArgumentException("Combiner aggs only take a single field as input. Got this instead: " + inputFields.toString());
        }
        _factory = new ComboList.Factory(groupFields.size(), inputFields.size());
    }
    

    @Override
    public void updateState(MapState map, List<TridentTuple> tuples, TridentCollector collector) {
        List<List<Object>> groups = new ArrayList<List<Object>>(tuples.size());
        List<ValueUpdater> updaters = new ArrayList<ValueUpdater>(tuples.size());
                
        for(TridentTuple t: tuples) {
            groups.add(_groupFactory.create(t));
            updaters.add(new CombinerValueUpdater(_agg,_inputFactory.create(t).getValue(0)));
        }
        List<Object> newVals = map.multiUpdate(groups, updaters);
       
        for(int i=0; i<tuples.size(); i++) {
            List<Object> key = groups.get(i);

View on GitHub (pinned to cdb116e942)