nathanmarz/storm · error · IllegalArgumentException
Bolt has already been declared for id
Error message
Bolt has already been declared for id ${id} What it means
TopologyBuilder.validateUnusedId throws IllegalArgumentException when setBolt is called with an id that is already registered as a bolt. Storm component ids must be unique across the topology, so reusing an id is rejected immediately at topology construction.
Solutions
- Rename one of the bolts so every component id is unique
- Generate ids programmatically (e.g. "bolt-" + index) to avoid collisions
- Use a fresh TopologyBuilder for each topology build instead of reusing one
- Search your topology code for duplicate setBolt calls with the same id
Example fix
// before
builder.setBolt("split", new SplitBolt());
builder.setBolt("split", new CountBolt()); // throws
// after
builder.setBolt("split", new SplitBolt());
builder.setBolt("count", new CountBolt()); Defensive patterns
Strategy: validation
Validate before calling
Set<String> used = new HashSet<>();
void safeBolt(TopologyBuilder b, String id, IRichBolt bolt) {
if (!used.add(id))
throw new IllegalStateException("duplicate component id: " + id);
b.setBolt(id, bolt);
} Try / catch
try {
builder.setBolt(id, bolt);
} catch (IllegalArgumentException e) {
if (!e.getMessage().contains("already been declared")) throw e;
// handle duplicate id: rename or skip
} Prevention
- Assign unique, descriptive ids to every component
- Never reuse a populated TopologyBuilder
- In generated topologies, assert id uniqueness before building
When it happens
Trigger: Calling builder.setBolt(id, ...) with an id previously passed to setBolt; a loop that re-declares bolts with a fixed or wrongly incremented id; topology code executed twice with the same builder.
Common situations: Copy-pasted bolt declarations with the same string id; ids generated without counters (e.g. constant "bolt"); rebuilding a topology on the same builder after a validation failure.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Spout has already been declared for id
- State spout has already been declared for id
- 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/328e36128e1ae99a.
Report an issue: GitHub.
Appendix: source
Thrown at storm-core/src/jvm/backtype/storm/topology/TopologyBuilder.java:212
validateUnusedId(id);
initCommon(id, spout, parallelism_hint);
_spouts.put(id, spout);
return new SpoutGetter(id);
}
public void setStateSpout(String id, IRichStateSpout stateSpout) {
setStateSpout(id, stateSpout, null);
}
public void setStateSpout(String id, IRichStateSpout stateSpout, Number parallelism_hint) {
validateUnusedId(id);
// TODO: finish
}
private void validateUnusedId(String id) {
if(_bolts.containsKey(id)) {
throw new IllegalArgumentException("Bolt has already been declared for id " + id);
}
if(_spouts.containsKey(id)) {
throw new IllegalArgumentException("Spout has already been declared for id " + id);
}
if(_stateSpouts.containsKey(id)) {
throw new IllegalArgumentException("State spout has already been declared for id " + id);
}
}
private ComponentCommon getComponentCommon(String id, IComponent component) {
ComponentCommon ret = new ComponentCommon(_commons.get(id));
OutputFieldsGetter getter = new OutputFieldsGetter();
component.declareOutputFields(getter);
ret.set_streams(getter.getFieldsDeclaration());
return ret;
}
View on GitHub (pinned to cdb116e942)