nathanmarz/storm · error · RuntimeException

State query operation can only have one parent

Error message

State query operation can only have one parent

What it means

StateQueryProcessor.prepare requires exactly one parent tuple factory because stateQuery reads from one input stream. If the parent count is not 1, prepare throws this RuntimeException. The state-query node was connected to multiple (or zero) upstream streams in the Trident graph.

Solutions

  1. Ensure stateQuery is applied to a Stream with a single parent; restructure joins/merges so the query node has in-degree 1.
  2. Apply stateQuery after the join output stream, not with join parents wired directly to it.
  3. Fix custom graph construction so the StateQueryProcessor node has exactly one incoming edge.
  4. Verify with the topology that only the intended stream feeds the state query.

Example fix

// before: two parents wired to the stateQuery node
joinNode -> stateQueryNode; s2 -> stateQueryNode;
// after: join output is the single parent
Stream joined = s1.join(s2, ...);
joined.stateQuery(stateFactory, fields, queryFunction);
Defensive patterns

Strategy: validation

Validate before calling

// Java: verify query node has a single parent before topology build
if (queryNode.getParents().size() != 1) {
    throw new IllegalArgumentException("stateQuery requires exactly one parent stream");
}

Try / catch

try { stream.stateQuery(...); } catch (RuntimeException e) { if (e.getMessage().contains("can only have one parent")) { throw new TopologyStructureException("stateQuery wired to multiple parents", e); } throw e; }

Prevention

When it happens

Trigger: Calling TridentTopology.newDRPCStream().stateQuery(...) or Stream.stateQuery(...) where the underlying node has multiple parent tuple factories, typically from manual graph wiring or querying a stream with several upstream edges.

Common situations: DRPC topologies where the query node got extra upstream edges from custom assembly; joins feeding stateQuery with unmerged parents; refactors adding inputs to a query node.

Understand the failure class

Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.

Related errors


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

Appendix: source

Thrown at storm-core/src/jvm/storm/trident/planner/processor/StateQueryProcessor.java:54

    QueryFunction _function;
    State _state;
    String _stateId;
    TridentContext _context;
    Fields _inputFields;
    ProjectionFactory _projection;
    AppendCollector _collector;
    
    public StateQueryProcessor(String stateId, Fields inputFields, QueryFunction function) {
        _stateId = stateId;
        _function = function;
        _inputFields = inputFields;
    }
    
    @Override
    public void prepare(Map conf, TopologyContext context, TridentContext tridentContext) {
        List<Factory> parents = tridentContext.getParentTupleFactories();
        if(parents.size()!=1) {
            throw new RuntimeException("State query operation can only have one parent");
        }
        _context = tridentContext;
        _state = (State) context.getTaskData(_stateId);
        _projection = new ProjectionFactory(parents.get(0), _inputFields);
        _collector = new AppendCollector(tridentContext);
        _function.prepare(conf, new TridentOperationContext(context, _projection));
    }

    @Override
    public void cleanup() {
        _function.cleanup();
    }

    @Override
    public void startBatch(ProcessorContext processorContext) {
        processorContext.state[_context.getStateIndex()] =  new BatchState();
    }

View on GitHub (pinned to cdb116e942)