nathanmarz/storm · error · IllegalArgumentException
Combiner state updater should receive a single tuple…
Error message
Combiner state updater should receive a single tuple. Received: ${tuples} What it means
CombinerAggStateUpdater performs state.update(new CombinerValueUpdater(agg, value)) which needs exactly one new value per call, so updateState asserts tuples.size()==1 and throws IllegalArgumentException otherwise. Combiner aggregators collapse a value, unlike reducers that accept a batch of tuples.
Solutions
- Use ReducerAggStateUpdater / ReducerAggregator semantics if you must process multiple tuples per update, or pre-combine upstream
- Ensure the stream feeding the combiner updater is grouped/partitioned so exactly one tuple reaches updateState
- Switch the operation to a CombinerAggregator-based persistentAggregate which guarantees single-value updates
Example fix
// before
stream.groupBy(g).persistentAggregate(state, new Fields("v"), new ReducerAggregator(), new MapCombinerAggStateUpdater(...));
// after
stream.groupBy(g).persistentAggregate(state, new Fields("v"), new Count(), new MapCombinerAggStateUpdater<>(new Count())); Defensive patterns
Strategy: validation
Validate before calling
if (tuples == null || tuples.size() != 1) {
throw new IllegalArgumentException("CombinerAggStateUpdater requires exactly one tuple, got " + (tuples == null ? 0 : tuples.size()));
} Type guard
boolean isSingleTuple(List<TridentTuple> tuples) {
return tuples != null && tuples.size() == 1;
} Try / catch
try {
updater.updateState(state, tuples, collector);
} catch (IllegalArgumentException e) {
if (e.getMessage().contains("should receive a single tuple")) {
throw new IllegalStateException("Use a Reducer-style updater for multi-tuple batches", e);
} throw e;
} Prevention
- Only pair CombinerAggregator with combiner state updaters
- Use ReducerAggStateUpdater for batch-style aggregation
- Test the persistentAggregate pipeline with real batch sizes
When it happens
Trigger: A persistentAggregate(newMapState, ..., new CombinerAggregator..., new MapCombinerAggStateUpdater...) whose upstream grouping/projection delivers 0 or >1 tuples to a single updateState invocation.
Common situations: Mis-wiring a combiner updater into a reducer-style aggregate chain; upstream partitioning collapsing/expanding tuples so multiple values arrive at once; hand-rolled state update calls passing a batch list.
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
- Cannot have one group have fixed parallelism of two…
- Output fields for chained aggregators must be distinct
- Require input fields for each aggregator
- Current batch (
- This state is read-only and does not support updates
AI-assisted analysis of nathanmarz/storm@cdb116e942 (2026-09-12).
Data as JSON: /api/errors/f8e49aefb110cf93.
Report an issue: GitHub.
Appendix: source
Thrown at storm-core/src/jvm/storm/trident/operation/impl/CombinerAggStateUpdater.java:42
import storm.trident.operation.TridentCollector;
import storm.trident.operation.TridentOperationContext;
import storm.trident.state.CombinerValueUpdater;
import storm.trident.state.StateUpdater;
import storm.trident.state.snapshot.Snapshottable;
import storm.trident.tuple.TridentTuple;
public class CombinerAggStateUpdater implements StateUpdater<Snapshottable> {
CombinerAggregator _agg;
public CombinerAggStateUpdater(CombinerAggregator agg) {
_agg = agg;
}
@Override
public void updateState(Snapshottable state, List<TridentTuple> tuples, TridentCollector collector) {
if(tuples.size()!=1) {
throw new IllegalArgumentException("Combiner state updater should receive a single tuple. Received: " + tuples.toString());
}
Object newVal = state.update(new CombinerValueUpdater(_agg, tuples.get(0).getValue(0)));
collector.emit(new Values(newVal));
}
@Override
public void prepare(Map conf, TridentOperationContext context) {
}
@Override
public void cleanup() {
}
}
View on GitHub (pinned to cdb116e942)