{"record":{"id":"e2d6c2738830b397","repo":"nathanmarz/storm","slug":"trident-only-supports-components-that-emit-a-single-stream","errorCode":null,"errorMessage":"Trident only supports components that emit a single stream","messagePattern":"Trident only supports components that emit a single stream","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"storm-core/src/jvm/storm/trident/util/TridentUtils.java","lineNumber":71,"sourceCode":"    }\n    \n    public static Fields fieldsSubtract(Fields all, Fields minus) {\n        Set<String> removeSet = new HashSet<String>(minus.toList());\n        List<String> toKeep = new ArrayList<String>();\n        for(String s: all.toList()) {\n            if(!removeSet.contains(s)) {\n                toKeep.add(s);\n            }\n        }\n        return new Fields(toKeep);\n    }\n    \n    public static Fields getSingleOutputStreamFields(IComponent component) {\n        OutputFieldsGetter getter = new OutputFieldsGetter();\n        component.declareOutputFields(getter);\n        Map<String, StreamInfo> declaration = getter.getFieldsDeclaration();\n        if(declaration.size()!=1) {\n            throw new RuntimeException(\"Trident only supports components that emit a single stream\");\n        }\n        StreamInfo si = declaration.values().iterator().next();\n        if(si.is_direct()) {\n            throw new RuntimeException(\"Trident does not support direct streams\");\n        }\n        return new Fields(si.get_output_fields());        \n    }\n    \n    /**\n     * Assumes edge contains an index\n     */\n    public static <T> List<T> getParents(DirectedGraph g, T n) {\n        List<IndexedEdge> incoming = new ArrayList(g.incomingEdgesOf(n));\n        Collections.sort(incoming);\n        List<T> ret = new ArrayList();\n        for(IndexedEdge e: incoming) {\n            ret.add((T)e.source);\n        }        ","sourceCodeStart":53,"sourceCodeEnd":89,"githubUrl":"https://github.com/nathanmarz/storm/blob/cdb116e942666973bc4eaa0df098d5bab82739e7/storm-core/src/jvm/storm/trident/util/TridentUtils.java#L53-L89","documentation":"Trident requires every component (spout or bolt) it wraps to declare exactly one output stream. getSingleOutputStreamFields calls declareOutputFields and inspects the declaration map; if the component declares zero or multiple streams, Trident cannot build its topology graph, so it throws this RuntimeException from TridentUtils.getSingleOutputStreamFields (TridentUtils.java:71).","triggerScenarios":"Calling Trident topology-building APIs (e.g. newStream(...).each/parallelismHint, TridentTopology operations) with a spout or bolt whose declareOutputFields registers more than one stream (e.g. two OutputFieldsDeclarer.declareStream calls, or a default declaration plus a named one).","commonSituations":"Reusing a plain Storm bolt that emits multiple named streams inside a Trident topology; copy-pasting a component that mixes declare() and declareStream(); building Trident topologies from legacy multi-stream spouts.","solutions":["Refactor the component to declare exactly one output stream (use a single declare() call).","Split the multi-stream component into separate single-stream components and wire them in Trident separately.","If you need Storm's multi-stream semantics, use a plain Storm topology instead of Trident.","If the declaration map is empty, add a declareOutputFields implementation that declares one stream."],"exampleFix":"// before\npublic void declareOutputFields(OutputFieldsDeclarer declarer) {\n    declarer.declareStream(\"a\", new Fields(\"x\"));\n    declarer.declareStream(\"b\", new Fields(\"y\"));\n}\n// after\npublic void declareOutputFields(OutputFieldsDeclarer declarer) {\n    declarer.declare(new Fields(\"x\", \"y\"));\n}","handlingStrategy":"validation","validationCode":"OutputFieldsGetter getter = new OutputFieldsGetter();\ncomponent.declareOutputFields(getter);\nif (getter.getFieldsDeclaration().size() != 1) {\n    throw new IllegalArgumentException(\"Component must declare exactly one stream for Trident\");\n}","typeGuard":"boolean isTridentCompatible(IComponent c) {\n    OutputFieldsGetter g = new OutputFieldsGetter();\n    c.declareOutputFields(g);\n    return g.getFieldsDeclaration().size() == 1;\n}","tryCatchPattern":null,"preventionTips":["Declare exactly one output stream in every component reused by Trident.","Never mix declare() with declareStream() in Trident-bound components.","Write a topology-construction test that touches all components early."],"tags":["trident","topology","stream-declaration","storm"],"backgroundTag":"unsupported-operation","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"}