{"record":{"id":"400a380b9ebea0d3","repo":"nathanmarz/storm","slug":"each-operation-can-only-have-one-parent","errorCode":null,"errorMessage":"Each operation can only have one parent","messagePattern":"Each operation can only have one parent","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"storm-core/src/jvm/storm/trident/planner/processor/EachProcessor.java","lineNumber":49,"sourceCode":"\n\npublic class EachProcessor implements TridentProcessor {\n    Function _function;\n    TridentContext _context;\n    AppendCollector _collector;\n    Fields _inputFields;\n    ProjectionFactory _projection;\n    \n    public EachProcessor(Fields inputFields, Function function) {\n        _function = function;\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(\"Each operation can only have one parent\");\n        }\n        _context = tridentContext;\n        _collector = new AppendCollector(tridentContext);\n        _projection = new ProjectionFactory(parents.get(0), _inputFields);\n        _function.prepare(conf, new TridentOperationContext(context, _projection));\n    }\n\n    @Override\n    public void cleanup() {\n        _function.cleanup();\n    }    \n\n    @Override\n    public void execute(ProcessorContext processorContext, String streamId, TridentTuple tuple) {\n        _collector.setContext(processorContext, tuple);\n        _function.execute(_projection.create(tuple), _collector);\n    }\n","sourceCodeStart":31,"sourceCodeEnd":67,"githubUrl":"https://github.com/nathanmarz/storm/blob/cdb116e942666973bc4eaa0df098d5bab82739e7/storm-core/src/jvm/storm/trident/planner/processor/EachProcessor.java#L31-L67","documentation":"EachProcessor.prepare requires exactly one parent tuple factory, because each() applies a function to a single input stream. When the Trident context reports a parent count other than 1, prepare throws this RuntimeException. The topology graph routes more than one stream (or none) into this each() node.","triggerScenarios":"A Trident topology where a each() node is wired to multiple parent streams, typically from programmatic graph construction or applying each() to a stream object that internally merged several parents without a single-parent intermediate node.","commonSituations":"Custom Trident planner/graph code; connecting two Streams into one Each node manually; version upgrades of Trident internals changing merge semantics so each() ends up with two parents.","solutions":["Apply each() to a single Stream chain; move each() before any merge/join that creates multiple parents.","If both streams need the function, apply each() to each stream separately before merging.","Use each() on the output of a join node rather than wiring two streams into one each node.","Audit custom Node/Edge construction so each EachProcessor node has in-degree 1."],"exampleFix":"// before\nStream both = s1; // graph wired with parents s1 and s2\nboth.each(getFields, func);\n// after\nStream a = s1.each(getFields, func);\nStream b = s2.each(getFields, func);\nStream out = a.merge(b);","handlingStrategy":"validation","validationCode":"// Java: structural pre-check in custom graph builders\nif (eachNode.getParents().size() != 1) {\n    throw new IllegalArgumentException(\"each() node must have exactly one parent, got \" + eachNode.getParents().size());\n}","typeGuard":null,"tryCatchPattern":"try { stream.each(...); } catch (RuntimeException e) { if (e.getMessage().contains(\"can only have one parent\")) { throw new TopologyStructureException(\"each() must sit on a single-parent stream\", e); } throw e; }","preventionTips":["Apply each() per-stream before merges","Use Stream.merge/join outputs (single node) as the each() input","Review custom Node/Edge code for accidental multi-edge connections"],"tags":["trident","topology-graph","each","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"}