nathanmarz/storm · error · RuntimeException
Regular rich spouts not supported yet... try wrapping in a…
Error message
Regular rich spouts not supported yet... try wrapping in a RichSpoutBatchExecutor
What it means
Trident topologies only accept spouts implementing IBatchSpout or ITridentSpout. During TridentTopology.build(), any spout node that is a plain Storm IRichSpout hits this else branch and a RuntimeException is thrown. Trident is batch-oriented and has no path for regular continuous spouts (the TODO comments note full support was never added).
Solutions
- Wrap the IRichSpout with RichSpoutBatchExecutor: TridentTopology.newStream(name, new RichSpoutBatchExecutor(spout))
- Implement ITridentSpout (or IBatchSpout) instead of IRichSpout
- Use an existing Trident-native connector for your data source
Example fix
// before
TridentTopology topology = new TridentTopology();
topology.newStream("spout", new MyRichSpout());
// after
topology.newStream("spout", new RichSpoutBatchExecutor(new MyRichSpout())); Defensive patterns
Strategy: type-guard
Validate before calling
if (!(spout instanceof IBatchSpout || spout instanceof ITridentSpout)) {
spout = new RichSpoutBatchExecutor((IRichSpout) spout);
} Type guard
boolean isTridentCompatible(Object spout) {
return spout instanceof IBatchSpout || spout instanceof ITridentSpout;
} Try / catch
try {
topology.newStream("s", spout);
} catch (RuntimeException e) {
if (e.getMessage().contains("Regular rich spouts not supported")) {
throw new IllegalStateException("Wrap IRichSpout in RichSpoutBatchExecutor before use", e);
} throw e;
} Prevention
- Never pass raw IRichSpout into TridentTopology.newStream
- Standardize a factory method that wraps spouts in RichSpoutBatchExecutor
- Prefer Trident-native spout implementations when available
When it happens
Trigger: newStream() fed from a spout created via topology.addSpout or TridentTopology.newStream(name, irichSpout) where the spout only implements IRichSpout, then calling build().
Common situations: Migrating an existing Storm topology to Trident and reusing the old IRichSpout; third-party connector spouts written for core Storm; tutorials mixing Trident API with classic spout implementations.
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
- Trying to select non-existent field
- Cannot join DRPC stream with streams originating from other…
- Parallelism is fixed to
- Cannot have one group have fixed parallelism of two…
- Output fields for chained aggregators must be distinct
AI-assisted analysis of nathanmarz/storm@cdb116e942 (2026-09-12).
Data as JSON: /api/errors/1c0465b6e54ef34c.
Report an issue: GitHub.
Appendix: source
Thrown at storm-core/src/jvm/storm/trident/TridentTopology.java:398
TridentTopologyBuilder builder = new TridentTopologyBuilder();
Map<Node, String> spoutIds = genSpoutIds(spoutNodes);
Map<Group, String> boltIds = genBoltIds(mergedGroups);
for(SpoutNode sn: spoutNodes) {
Integer parallelism = parallelisms.get(grouper.nodeGroup(sn));
if(sn.type == SpoutNode.SpoutType.DRPC) {
builder.setBatchPerTupleSpout(spoutIds.get(sn), sn.streamId,
(IRichSpout) sn.spout, parallelism, batchGroupMap.get(sn));
} else {
ITridentSpout s;
if(sn.spout instanceof IBatchSpout) {
s = new BatchSpoutExecutor((IBatchSpout)sn.spout);
} else if(sn.spout instanceof ITridentSpout) {
s = (ITridentSpout) sn.spout;
} else {
throw new RuntimeException("Regular rich spouts not supported yet... try wrapping in a RichSpoutBatchExecutor");
// TODO: handle regular rich spout without batches (need lots of updates to support this throughout)
}
builder.setSpout(spoutIds.get(sn), sn.streamId, sn.txId, s, parallelism, batchGroupMap.get(sn));
}
}
for(Group g: mergedGroups) {
if(!isSpoutGroup(g)) {
Integer p = parallelisms.get(g);
Map<String, String> streamToGroup = getOutputStreamBatchGroups(g, batchGroupMap);
BoltDeclarer d = builder.setBolt(boltIds.get(g), new SubtopologyBolt(graph, g.nodes, batchGroupMap), p,
committerBatches(g, batchGroupMap), streamToGroup);
Collection<PartitionNode> inputs = uniquedSubscriptions(externalGroupInputs(g));
for(PartitionNode n: inputs) {
Node parent = TridentUtils.getParent(graph, n);
String componentId;
if(parent instanceof SpoutNode) {
componentId = spoutIds.get(parent);View on GitHub (pinned to cdb116e942)