nathanmarz/storm · error · RuntimeException
Results size is different than argument size:
Error message
Results size is different than argument size:
What it means
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.
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.
Example fix
// before
public List<Object> batchRetrieve(State state, List<TridentTuple> args) {
return store.multiGet(keys).stream().filter(Objects::nonNull).collect(toList());
}
// after: keep positional alignment, null for misses
List<Object> raw = store.multiGet(keys);
List<Object> results = new ArrayList<>(args.size());
for (Object r : raw) results.add(r == null ? null : r);
return results; Defensive patterns
Strategy: try-catch
Validate before calling
// Java: inside your QueryFunction, assert alignment before returning
if (results.size() != args.size()) {
throw new IllegalStateException("batchRetrieve must return 1 result per arg; got " + results.size() + " for " + args.size());
} Try / catch
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; } Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- State query operation can only have one parent
- Trying to select non-existent field
- Regular rich spouts not supported yet... try wrapping in a…
- Cannot join DRPC stream with streams originating from other…
- Parallelism is fixed to
AI-assisted analysis of nathanmarz/storm@cdb116e942 (2026-09-12).
Data as JSON: /api/errors/6ac97af6d5f4b0ee.
Report an issue: GitHub.
Appendix: source
Thrown at storm-core/src/jvm/storm/trident/planner/processor/StateQueryProcessor.java:86
@Override
public void startBatch(ProcessorContext processorContext) {
processorContext.state[_context.getStateIndex()] = new BatchState();
}
@Override
public void execute(ProcessorContext processorContext, String streamId, TridentTuple tuple) {
BatchState state = (BatchState) processorContext.state[_context.getStateIndex()];
state.tuples.add(tuple);
state.args.add(_projection.create(tuple));
}
@Override
public void finishBatch(ProcessorContext processorContext) {
BatchState state = (BatchState) processorContext.state[_context.getStateIndex()];
if(!state.tuples.isEmpty()) {
List<Object> results = _function.batchRetrieve(_state, state.args);
if(results.size()!=state.tuples.size()) {
throw new RuntimeException("Results size is different than argument size: " + results.size() + " vs " + state.tuples.size());
}
for(int i=0; i<state.tuples.size(); i++) {
TridentTuple tuple = state.tuples.get(i);
Object result = results.get(i);
_collector.setContext(processorContext, tuple);
_function.execute(_projection.create(tuple), result, _collector);
}
}
}
private static class BatchState {
public List<TridentTuple> tuples = new ArrayList<TridentTuple>();
public List<TridentTuple> args = new ArrayList<TridentTuple>();
}
@Override
public Factory getOutputFactory() {
return _collector.getOutputFactory();View on GitHub (pinned to cdb116e942)