nathanmarz/storm · error · InvalidTopologyException
Topology submission exception
Error message
Topology submission exception
What it means
StormSubmitter.submitTopology() catches InvalidTopologyException thrown by Nimbus when the submitted topology fails server-side validation (e.g. miswired streams, unbolted spouts, missing declared fields). It logs the exception with the message 'Topology submission exception' and rethrows it, so the caller's submission fails. It is a deliberate server-side rejection of the topology definition, not a transient fault.
Solutions
- Read the nested InvalidTopologyException message — it names the specific component/stream that failed validation.
- Check every setBolt(...).shuffleGrouping/fieldsGrouping(...) references an existing component and stream id.
- Verify declared output fields of each spout/bolt match what downstream bolts consume (declareOutputFields).
- Validate the topology in LocalCluster mode before submitting to the cluster.
- Fix the invalid wiring and resubmit; the fix is always in the topology definition, not cluster config.
Example fix
// before
builder.setBolt("count", new CountBolt())
.fieldsGrouping("splitter", "word-stream", new Fields("word")); // splitter never declared this stream
// after
builder.setBolt("split", new SplitSentenceBolt());
builder.setBolt("count", new CountBolt())
.fieldsGrouping("split", new Fields("word")); Defensive patterns
Strategy: validation
Validate before calling
// validate wiring before submitTopology
for (String bolt : builder.getBoltIds()) {
for (String upstream : builder.getBolt(bolt).getGroupings().keySet()) {
if (!builder.getBoltIds().contains(upstream) && !builder.getSpoutIds().contains(upstream))
throw new IllegalStateException(bolt + " consumes from unknown component: " + upstream);
}
} Try / catch
try {
StormSubmitter.submitTopology(name, conf, topology);
} catch (InvalidTopologyException e) {
LOG.error("Topology rejected by Nimbus: " + e.get_msg(), e);
throw new IllegalArgumentException("Fix topology wiring: " + e.get_msg(), e);
} Prevention
- Test the topology in LocalCluster before every cluster submission.
- Keep component ids and stream ids as named constants to avoid typos.
- Verify declareOutputFields matches every consuming grouping's Fields.
- Run topology wiring checks in CI (build topology and submit to local mode).
When it happens
Trigger: Calling StormSubmitter.submitTopology(...) with a topology that Nimbus's validation rejects: a spout/bolt declares input/output streams incorrectly, a component is not wired (setSpout/setBolt mismatches), or grouping references a non-existent stream/component.
Common situations: Topology built programmatically with wrong stream/field names; refactor renamed a component but groupings reference the old one; empty or malformed component declarations; serialization problems in declared fields; version drift where a previously accepted topology shape is rejected.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- Topology already alive exception
- Must manage at least one spout
- A single worker should have 1 SystemBolt instance.
- No output fields defined for component:stream
- Fields for already set
AI-assisted analysis of nathanmarz/storm@cdb116e942 (2026-09-12).
Data as JSON: /api/errors/e40024591fb955bc.
Report an issue: GitHub.
Appendix: source
Thrown at storm-core/src/jvm/backtype/storm/StormSubmitter.java:101
if(localNimbus!=null) {
LOG.info("Submitting topology " + name + " in local mode");
localNimbus.submitTopology(name, null, serConf, topology);
} else {
NimbusClient client = NimbusClient.getConfiguredClient(conf);
if(topologyNameExists(conf, name)) {
throw new RuntimeException("Topology with name `" + name + "` already exists on cluster");
}
submitJar(conf);
try {
LOG.info("Submitting topology " + name + " in distributed mode with conf " + serConf);
if(opts!=null) {
client.getClient().submitTopologyWithOpts(name, submittedJar, serConf, topology, opts);
} else {
// this is for backwards compatibility
client.getClient().submitTopology(name, submittedJar, serConf, topology);
}
} catch(InvalidTopologyException e) {
LOG.warn("Topology submission exception", e);
throw e;
} catch(AlreadyAliveException e) {
LOG.warn("Topology already alive exception", e);
throw e;
} finally {
client.close();
}
}
LOG.info("Finished submitting topology: " + name);
} catch(TException e) {
throw new RuntimeException(e);
}
}
private static boolean topologyNameExists(Map conf, String name) {
NimbusClient client = NimbusClient.getConfiguredClient(conf);
try {
ClusterSummary summary = client.getClient().getClusterInfo();View on GitHub (pinned to cdb116e942)