{"record":{"id":"6ac97af6d5f4b0ee","repo":"nathanmarz/storm","slug":"results-size-is-different-than-argument-size","errorCode":null,"errorMessage":"Results size is different than argument size: ","messagePattern":"Results size is different than argument size: ","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"storm-core/src/jvm/storm/trident/planner/processor/StateQueryProcessor.java","lineNumber":86,"sourceCode":"    @Override\n    public void startBatch(ProcessorContext processorContext) {\n        processorContext.state[_context.getStateIndex()] =  new BatchState();\n    }\n\n    @Override\n    public void execute(ProcessorContext processorContext, String streamId, TridentTuple tuple) {\n        BatchState state = (BatchState) processorContext.state[_context.getStateIndex()];\n        state.tuples.add(tuple);\n        state.args.add(_projection.create(tuple));\n    }\n\n    @Override\n    public void finishBatch(ProcessorContext processorContext) {\n        BatchState state = (BatchState) processorContext.state[_context.getStateIndex()];\n        if(!state.tuples.isEmpty()) {\n            List<Object> results = _function.batchRetrieve(_state, state.args);\n            if(results.size()!=state.tuples.size()) {\n                throw new RuntimeException(\"Results size is different than argument size: \" + results.size() + \" vs \" + state.tuples.size());\n            }\n            for(int i=0; i<state.tuples.size(); i++) {\n                TridentTuple tuple = state.tuples.get(i);\n                Object result = results.get(i);\n                _collector.setContext(processorContext, tuple);\n                _function.execute(_projection.create(tuple), result, _collector);            \n            }\n        }\n    }\n    \n    private static class BatchState {\n        public List<TridentTuple> tuples = new ArrayList<TridentTuple>();\n        public List<TridentTuple> args = new ArrayList<TridentTuple>();\n    }\n\n    @Override\n    public Factory getOutputFactory() {\n        return _collector.getOutputFactory();","sourceCodeStart":68,"sourceCodeEnd":104,"githubUrl":"https://github.com/nathanmarz/storm/blob/cdb116e942666973bc4eaa0df098d5bab82739e7/storm-core/src/jvm/storm/trident/planner/processor/StateQueryProcessor.java#L68-L104","documentation":"StateQueryProcessor.finishBatch calls the QueryFunction's batchRetrieve and requires it to return exactly one result per input argument tuple. If results.size() != tuples.size(), it throws this RuntimeException naming the two sizes. This enforces the QueryFunction contract that batchRetrieve returns aligned, one-to-one results for every requested key.","triggerScenarios":"A custom QueryFunction's batchRetrieve returns fewer (or more) results than the number of argument tuples — e.g. skipping tuples whose key was not found in the State, returning null-less filtered lists, or a State implementation returning partial results.","commonSituations":"Custom State/BackingMap implementations that drop missing keys instead of returning null placeholders; caching layers returning only hits; DRPC state queries against a state store with inconsistent batch retrieval semantics.","solutions":["Fix your QueryFunction.batchRetrieve to return exactly one entry per input argument — add null (or a sentinel) for keys not found.","Check the State implementation's multiGet/batchRetrieve for filtering behavior; wrap it to pad missing results to null.","Verify no deduplication/sorting is applied to the results list before returning.","Log results.size() vs state.tuples.size() inside the QueryFunction to find which tuples are dropped."],"exampleFix":"// before\npublic List<Object> batchRetrieve(State state, List<TridentTuple> args) {\n    return store.multiGet(keys).stream().filter(Objects::nonNull).collect(toList());\n}\n// after: keep positional alignment, null for misses\nList<Object> raw = store.multiGet(keys);\nList<Object> results = new ArrayList<>(args.size());\nfor (Object r : raw) results.add(r == null ? null : r);\nreturn results;","handlingStrategy":"try-catch","validationCode":"// Java: inside your QueryFunction, assert alignment before returning\nif (results.size() != args.size()) {\n    throw new IllegalStateException(\"batchRetrieve must return 1 result per arg; got \" + results.size() + \" for \" + args.size());\n}","typeGuard":null,"tryCatchPattern":"try { processorContextNext(node); } catch (RuntimeException e) { if (e.getMessage().startsWith(\"Results size is different than argument size\")) { log.error(\"QueryFunction returned misaligned batch: {}\", e.getMessage()); } throw e; }","preventionTips":["Always return one result per input tuple, null for misses","Never filter or dedupe the batchRetrieve results list","Unit-test custom QueryFunctions against arg lists containing missing keys"],"tags":["trident","state-query","batch-retrieve","contract-violation"],"backgroundTag":"unexpected-response-shape","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"}