{"record":{"id":"c79f0581430f19b1","repo":"nathanmarz/storm","slug":"projection-processor-can-only-have-one-parent","errorCode":null,"errorMessage":"Projection processor can only have one parent","messagePattern":"Projection processor can only have one parent","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"storm-core/src/jvm/storm/trident/planner/processor/ProjectedProcessor.java","lineNumber":43,"sourceCode":"import storm.trident.planner.TupleReceiver;\nimport storm.trident.tuple.TridentTuple;\nimport storm.trident.tuple.TridentTuple.Factory;\nimport storm.trident.tuple.TridentTupleView.ProjectionFactory;\n\n\npublic class ProjectedProcessor implements TridentProcessor {\n    Fields _projectFields;\n    ProjectionFactory _factory;\n    TridentContext _context;\n    \n    public ProjectedProcessor(Fields projectFields) {\n        _projectFields = projectFields;\n    }\n    \n    @Override\n    public void prepare(Map conf, TopologyContext context, TridentContext tridentContext) {\n        if(tridentContext.getParentTupleFactories().size()!=1) {\n            throw new RuntimeException(\"Projection processor can only have one parent\");\n        }\n        _context = tridentContext;\n        _factory = new ProjectionFactory(tridentContext.getParentTupleFactories().get(0), _projectFields);\n    }\n\n    @Override\n    public void cleanup() {\n    }\n\n    @Override\n    public void startBatch(ProcessorContext processorContext) {\n    }\n\n    @Override\n    public void execute(ProcessorContext processorContext, String streamId, TridentTuple tuple) {\n        TridentTuple toEmit = _factory.create(tuple);\n        for(TupleReceiver r: _context.getReceivers()) {\n            r.execute(processorContext, _context.getOutStreamId(), toEmit);","sourceCodeStart":25,"sourceCodeEnd":61,"githubUrl":"https://github.com/nathanmarz/storm/blob/cdb116e942666973bc4eaa0df098d5bab82739e7/storm-core/src/jvm/storm/trident/planner/processor/ProjectedProcessor.java#L25-L61","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: projection with two parents\nprojectionNode parents = [s1, s2];\n// after\nStream p1 = s1.project(projectFields);\nStream p2 = s2.project(projectFields);\nStream out = p1.merge(p2);","handlingStrategy":"validation","validationCode":"// Java: ensure projection node has one parent before graph build\nif (projectNode.getParents().size() != 1) {\n    throw new IllegalArgumentException(\"project() requires a single parent stream\");\n}","typeGuard":null,"tryCatchPattern":"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; }","preventionTips":["Project each source stream before merging","Place project() after join outputs, not on raw multi-parent wiring","Keep projections early in linear chains"],"tags":["trident","projection","topology-graph","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"}