{"record":{"id":"3975dbd9938bd5c8","repo":"nathanmarz/storm","slug":"multireducer-groupfields-and-inputfields-must-be-the-same","errorCode":null,"errorMessage":"Multireducer groupFields and inputFields must be the same size","messagePattern":"Multireducer groupFields and inputFields must be the same size","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"storm-core/src/jvm/storm/trident/operation/impl/GroupedMultiReducerExecutor.java","lineNumber":42,"sourceCode":"import java.util.Map;\nimport storm.trident.operation.GroupedMultiReducer;\nimport storm.trident.operation.MultiReducer;\nimport storm.trident.operation.TridentCollector;\nimport storm.trident.operation.TridentMultiReducerContext;\nimport storm.trident.tuple.TridentTuple;\nimport storm.trident.tuple.TridentTupleView.ProjectionFactory;\n\n\npublic class GroupedMultiReducerExecutor implements MultiReducer<Map<TridentTuple, Object>> {\n    GroupedMultiReducer _reducer;\n    List<Fields> _groupFields;\n    List<Fields> _inputFields;\n    List<ProjectionFactory> _groupFactories = new ArrayList<ProjectionFactory>();\n    List<ProjectionFactory> _inputFactories = new ArrayList<ProjectionFactory>();\n    \n    public GroupedMultiReducerExecutor(GroupedMultiReducer reducer, List<Fields> groupFields, List<Fields> inputFields) {\n        if(inputFields.size()!=groupFields.size()) {\n            throw new IllegalArgumentException(\"Multireducer groupFields and inputFields must be the same size\");\n        }\n        _groupFields = groupFields;\n        _inputFields = inputFields;\n        _reducer = reducer;\n    }\n    \n    @Override\n    public void prepare(Map conf, TridentMultiReducerContext context) {\n        for(int i=0; i<_groupFields.size(); i++) {\n            _groupFactories.add(context.makeProjectionFactory(i, _groupFields.get(i)));\n            _inputFactories.add(context.makeProjectionFactory(i, _inputFields.get(i)));\n        }\n        _reducer.prepare(conf, new TridentMultiReducerContext((List) _inputFactories));\n    }\n\n    @Override\n    public Map<TridentTuple, Object> init(TridentCollector collector) {\n        return new HashMap();","sourceCodeStart":24,"sourceCodeEnd":60,"githubUrl":"https://github.com/nathanmarz/storm/blob/cdb116e942666973bc4eaa0df098d5bab82739e7/storm-core/src/jvm/storm/trident/operation/impl/GroupedMultiReducerExecutor.java#L24-L60","documentation":"GroupedMultiReducerExecutor wraps a GroupedMultiReducer and maintains parallel lists of group fields and input fields, one entry per reduce stream. The constructor requires inputFields.size() == groupFields.size() and throws IllegalArgumentException otherwise, since each stream's group spec needs a matching input spec.","triggerScenarios":"Calling multiReduce(groupFields, streams, reducer) or constructing GroupedMultiReducerExecutor directly where the List<Fields> for grouping and for inputs have different lengths (e.g. one group Fields per stream but a single combined input Fields).","commonSituations":"Passing a single Fields for all streams' inputs while listing per-stream group fields; programmatically building the lists and dropping an entry; API confusion between the two multiReduce overloads.","solutions":["Supply one input Fields per stream so the lists are parallel: multiReduce(groupFields, inputFields, streams, reducer)","If all streams share the same grouping/inputs, use the single-Fields multiReduce overload instead of lists","Check list sizes before constructing and log both lists when debugging"],"exampleFix":"// before\nmultiReduce(Arrays.asList(gf1), stream1.and(stream2), Arrays.asList(in1, in2), reducer); // sizes mismatch\n// after\nmultiReduce(Arrays.asList(gf1, gf1), Arrays.asList(in1, in2), stream1.and(stream2), reducer);","handlingStrategy":"type-guard","validationCode":"if (groupFields.size() != inputFields.size()) {\n    throw new IllegalArgumentException(\"groupFields and inputFields lists must be parallel: \" + groupFields.size() + \" vs \" + inputFields.size());\n}","typeGuard":"boolean listsAreParallel(List<Fields> a, List<Fields> b) {\n    return a != null && b != null && a.size() == b.size();\n}","tryCatchPattern":"try {\n    stream.multiReduce(groupFields, inputFields, streams, reducer);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"must be the same size\")) {\n        throw new IllegalStateException(\"Provide one group Fields and one input Fields per stream\", e);\n    } throw e;\n}","preventionTips":["Always build groupFields/inputFields lists in the same loop over streams","Use the single-Fields multiReduce overload when all streams share specs","Unit-test multiReduce wiring before submitting the topology"],"tags":["storm","trident","multireducer","constructor"],"backgroundTag":"invalid-constructor-argument","analyzedSha":"cdb116e942666973bc4eaa0df098d5bab82739e7","analyzedAt":"2026-09-12T14:30:00.714Z","contentChangedAt":"2026-09-12T14:30:00.714Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}