nathanmarz/storm · error · RuntimeException

Trident does not support direct streams

Error message

Trident does not support direct streams

What it means

Trident does not support direct streams (streams declared with direct grouping, where the downstream decides routing). After checking that a component declares a single stream, getSingleOutputStreamFields inspects StreamInfo.is_direct(); a direct declaration is rejected with this RuntimeException at TridentUtils.java:75.

Solutions

  1. Remove the direct flag from the component's stream declaration (declare non-direct fields).
  2. Replace direct-grouping logic with a Trident-supported grouping (shuffle, fields, etc.).
  3. Move the component to a plain Storm topology if direct streams are required.

Example fix

// before
declarer.declareStream("out", true, new Fields("word"));
// after
declarer.declare(new Fields("word"));
Defensive patterns

Strategy: validation

Validate before calling

OutputFieldsGetter getter = new OutputFieldsGetter();
component.declareOutputFields(getter);
for (StreamInfo si : getter.getFieldsDeclaration().values()) {
    if (si.is_direct()) throw new IllegalArgumentException("Direct streams are not supported by Trident");
}

Prevention

When it happens

Trigger: Passing to Trident any component whose declareOutputFields uses declarer.declareStream(name, true, fields) or otherwise marks the stream as direct, then invoking Trident topology construction (newStream, each, etc.).

Common situations: Reusing Storm bolts that use direct streams for custom grouping inside Trident; porting components written for partialKeyGrouping or custom routing patterns; copying Storm examples into a Trident codebase.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


AI-assisted analysis of nathanmarz/storm@cdb116e942 (2026-09-12). Data as JSON: /api/errors/41dc75e40248a4c3. Report an issue: GitHub.

Appendix: source

Thrown at storm-core/src/jvm/storm/trident/util/TridentUtils.java:75

        List<String> toKeep = new ArrayList<String>();
        for(String s: all.toList()) {
            if(!removeSet.contains(s)) {
                toKeep.add(s);
            }
        }
        return new Fields(toKeep);
    }
    
    public static Fields getSingleOutputStreamFields(IComponent component) {
        OutputFieldsGetter getter = new OutputFieldsGetter();
        component.declareOutputFields(getter);
        Map<String, StreamInfo> declaration = getter.getFieldsDeclaration();
        if(declaration.size()!=1) {
            throw new RuntimeException("Trident only supports components that emit a single stream");
        }
        StreamInfo si = declaration.values().iterator().next();
        if(si.is_direct()) {
            throw new RuntimeException("Trident does not support direct streams");
        }
        return new Fields(si.get_output_fields());        
    }
    
    /**
     * Assumes edge contains an index
     */
    public static <T> List<T> getParents(DirectedGraph g, T n) {
        List<IndexedEdge> incoming = new ArrayList(g.incomingEdgesOf(n));
        Collections.sort(incoming);
        List<T> ret = new ArrayList();
        for(IndexedEdge e: incoming) {
            ret.add((T)e.source);
        }        
        return ret;
    }

    public static <T> List<T> getChildren(DirectedGraph g, T n) {

View on GitHub (pinned to cdb116e942)