nathanmarz/storm · error · RuntimeException
Each operation can only have one parent
Error message
Each operation can only have one parent
What it means
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.
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.
Example fix
// before Stream both = s1; // graph wired with parents s1 and s2 both.each(getFields, func); // after Stream a = s1.each(getFields, func); Stream b = s2.each(getFields, func); Stream out = a.merge(b);
Defensive patterns
Strategy: validation
Validate before calling
// Java: structural pre-check in custom graph builders
if (eachNode.getParents().size() != 1) {
throw new IllegalArgumentException("each() node must have exactly one parent, got " + eachNode.getParents().size());
} Try / catch
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; } Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
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
- Aggregate operation can only have one parent
- Projection processor can only have one parent
- Partition persist operation can only have one parent
- State query operation can only have one parent
- Trying to select non-existent field
AI-assisted analysis of nathanmarz/storm@cdb116e942 (2026-09-12).
Data as JSON: /api/errors/400a380b9ebea0d3.
Report an issue: GitHub.
Appendix: source
Thrown at storm-core/src/jvm/storm/trident/planner/processor/EachProcessor.java:49
public class EachProcessor implements TridentProcessor {
Function _function;
TridentContext _context;
AppendCollector _collector;
Fields _inputFields;
ProjectionFactory _projection;
public EachProcessor(Fields inputFields, Function function) {
_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("Each operation can only have one parent");
}
_context = tridentContext;
_collector = new AppendCollector(tridentContext);
_projection = new ProjectionFactory(parents.get(0), _inputFields);
_function.prepare(conf, new TridentOperationContext(context, _projection));
}
@Override
public void cleanup() {
_function.cleanup();
}
@Override
public void execute(ProcessorContext processorContext, String streamId, TridentTuple tuple) {
_collector.setContext(processorContext, tuple);
_function.execute(_projection.create(tuple), _collector);
}
View on GitHub (pinned to cdb116e942)