{"record":{"id":"41d723b8d6f2ca94","repo":"nathanmarz/storm","slug":"partition-persist-operation-can-only-have-one-parent","errorCode":null,"errorMessage":"Partition persist operation can only have one parent","messagePattern":"Partition persist operation can only have one parent","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"storm-core/src/jvm/storm/trident/planner/processor/PartitionPersistProcessor.java","lineNumber":55,"sourceCode":"    StateUpdater _updater;\n    State _state;\n    String _stateId;\n    TridentContext _context;\n    Fields _inputFields;\n    ProjectionFactory _projection;\n    FreshCollector _collector;\n\n    public PartitionPersistProcessor(String stateId, Fields inputFields, StateUpdater updater) {\n        _updater = updater;\n        _stateId = stateId;\n        _inputFields = inputFields;\n    }\n    \n    @Override\n    public void prepare(Map conf, TopologyContext context, TridentContext tridentContext) {\n        List<Factory> parents = tridentContext.getParentTupleFactories();\n        if(parents.size()!=1) {\n            throw new RuntimeException(\"Partition persist operation can only have one parent\");\n        }\n        _context = tridentContext;\n        _state = (State) context.getTaskData(_stateId);\n        _projection = new ProjectionFactory(parents.get(0), _inputFields);\n        _collector = new FreshCollector(tridentContext);\n        _updater.prepare(conf, new TridentOperationContext(context, _projection));\n    }\n\n    @Override\n    public void cleanup() {\n        _updater.cleanup();\n    }\n\n    @Override\n    public void startBatch(ProcessorContext processorContext) {\n        processorContext.state[_context.getStateIndex()] = new ArrayList<TridentTuple>();        \n    }\n    ","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/nathanmarz/storm/blob/cdb116e942666973bc4eaa0df098d5bab82739e7/storm-core/src/jvm/storm/trident/planner/processor/PartitionPersistProcessor.java#L37-L73","documentation":"PartitionPersistProcessor.prepare requires exactly one parent tuple factory because partitionPersist writes one input stream into a State. If the Trident context reports any other parent count, prepare throws this RuntimeException. The persist node was connected to multiple (or zero) upstream streams.","triggerScenarios":"Calling partitionPersist (or persistentAggregate) on a Stream whose graph node has multiple parents — e.g. persisting a merged/joined stream whose merge was wired to leave the persist node with several incoming edges.","commonSituations":"Persisting the result of a custom multi-parent merge; programmatic Trident graph assembly; stateful topologies where users wire two data sources into one persist node.","solutions":["Ensure partitionPersist is invoked on a Stream whose node has a single parent; insert the persist after a proper merge/join output.","If two streams must feed one state, aggregate/merge them into a single-parent chain first.","Verify custom graph edges so the persist node has in-degree 1.","Use persistentAggregate, which handles its own single-parent wiring, where appropriate."],"exampleFix":"// before: persist node with two parents\nnewStream1.merge(newStream2).partitionPersist(stateFactory, fields, updater);\n// after: reduce to single-parent chain first\nStream merged = topology.merge(newStream1, newStream2); // merge node is the single parent\nmerged.partitionPersist(stateFactory, fields, updater);","handlingStrategy":"validation","validationCode":"// Java: check persist node in-degree before building\nif (persistNode.getParents().size() != 1) {\n    throw new IllegalArgumentException(\"partitionPersist needs exactly one parent stream\");\n}","typeGuard":null,"tryCatchPattern":"try { stream.partitionPersist(...); } catch (RuntimeException e) { if (e.getMessage().contains(\"can only have one parent\")) { throw new TopologyStructureException(\"Persist node wired to multiple parents\", e); } throw e; }","preventionTips":["Persist only single-parent chains; merge first, persist after","Prefer persistentAggregate for stateful aggregation flows","Keep state persistence at the end of linear stream chains"],"tags":["trident","state","partition-persist","invalid-wiring"],"backgroundTag":"incompatible-source-type","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"}