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
- Remove the direct flag from the component's stream declaration (declare non-direct fields).
- Replace direct-grouping logic with a Trident-supported grouping (shuffle, fields, etc.).
- 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
- Never pass `true` as the direct flag in components used with Trident.
- Prefer standard Trident groupings over custom direct routing.
- Audit reused Storm bolts for direct declarations before adding them to Trident topologies.
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
- Trident only supports components that emit a single stream
- Must declare exactly one stream from last bolt in…
- Trying to select non-existent field
- Regular rich spouts not supported yet... try wrapping in a…
- Cannot join DRPC stream with streams originating from other…
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)