nathanmarz/storm · error · RuntimeException
Projection processor can only have one parent
Error message
Projection processor can only have one parent
What it means
ProjectedProcessor.prepare requires exactly one parent tuple factory because a projection re-projects one input stream's fields. If the parent count differs from 1, prepare throws this RuntimeException. The project() node received multiple upstream streams.
Solutions
- Move project() to a point in the topology where the stream has exactly one parent.
- Apply the projection to each source stream separately before merging.
- If projecting after a join, ensure the join node itself is the single parent of the projection node.
- Fix custom Node/Edge wiring so the ProjectedProcessor has in-degree 1.
Example fix
// before: projection with two parents projectionNode parents = [s1, s2]; // after Stream p1 = s1.project(projectFields); Stream p2 = s2.project(projectFields); Stream out = p1.merge(p2);
Defensive patterns
Strategy: validation
Validate before calling
// Java: ensure projection node has one parent before graph build
if (projectNode.getParents().size() != 1) {
throw new IllegalArgumentException("project() requires a single parent stream");
} Try / catch
try { stream.project(fields); } catch (RuntimeException e) { if (e.getMessage().contains("can only have one parent")) { throw new TopologyStructureException("Projection applied to multi-parent node", e); } throw e; } Prevention
- Project each source stream before merging
- Place project() after join outputs, not on raw multi-parent wiring
- Keep projections early in linear chains
When it happens
Trigger: Applying Stream.project(...) at a graph position where the node has multiple parents, usually from programmatic graph assembly or projection placed directly on a multi-parent merge/join wiring.
Common situations: Projecting fields immediately after custom merges; custom Trident graph builders connecting several streams into a projection node; refactors that add a second upstream edge to a projected 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
- Aggregate operation can only have one parent
- Each operation 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/c79f0581430f19b1.
Report an issue: GitHub.
Appendix: source
Thrown at storm-core/src/jvm/storm/trident/planner/processor/ProjectedProcessor.java:43
import storm.trident.planner.TupleReceiver;
import storm.trident.tuple.TridentTuple;
import storm.trident.tuple.TridentTuple.Factory;
import storm.trident.tuple.TridentTupleView.ProjectionFactory;
public class ProjectedProcessor implements TridentProcessor {
Fields _projectFields;
ProjectionFactory _factory;
TridentContext _context;
public ProjectedProcessor(Fields projectFields) {
_projectFields = projectFields;
}
@Override
public void prepare(Map conf, TopologyContext context, TridentContext tridentContext) {
if(tridentContext.getParentTupleFactories().size()!=1) {
throw new RuntimeException("Projection processor can only have one parent");
}
_context = tridentContext;
_factory = new ProjectionFactory(tridentContext.getParentTupleFactories().get(0), _projectFields);
}
@Override
public void cleanup() {
}
@Override
public void startBatch(ProcessorContext processorContext) {
}
@Override
public void execute(ProcessorContext processorContext, String streamId, TridentTuple tuple) {
TridentTuple toEmit = _factory.create(tuple);
for(TupleReceiver r: _context.getReceivers()) {
r.execute(processorContext, _context.getOutStreamId(), toEmit);View on GitHub (pinned to cdb116e942)