nathanmarz/storm · error · IllegalArgumentException
State spout has already been declared for id
Error message
State spout has already been declared for id ${id} What it means
TopologyBuilder.validateUnusedId throws IllegalArgumentException when a component id collides with an already-registered state spout (_stateSpouts). Ids must be unique across all component kinds in the topology.
Solutions
- Use a distinct id for the state spout
- Ensure generated ids are namespaced per component kind (e.g. "state-" + name)
- Use a fresh TopologyBuilder for each build
- Check for duplicate setStateSpout calls with the same id
Example fix
// before
builder.setStateSpout("tx", new MyStateSpout());
builder.setSpout("tx", new TransactionalSpout()); // throws
// after
builder.setStateSpout("tx-state", new MyStateSpout());
builder.setSpout("tx", new TransactionalSpout()); Defensive patterns
Strategy: validation
Validate before calling
Set<String> used = new HashSet<>();
void safeStateSpout(TopologyBuilder b, String id, IStateSpout ss) {
if (!used.add(id))
throw new IllegalStateException("duplicate component id: " + id);
b.setStateSpout(id, ss);
} Try / catch
try {
builder.setStateSpout(id, stateSpout);
} catch (IllegalArgumentException e) {
if (!e.getMessage().contains("already been declared")) throw e;
// handle duplicate id
} Prevention
- Namespace state spout ids distinctly from bolts/spouts
- Check the whole topology (bolts + spouts + state spouts) for id uniqueness before build
- Never reuse a populated TopologyBuilder
When it happens
Trigger: Declaring a state spout (or bolt/spout) with an id already present in _stateSpouts via setStateSpout; loops re-declaring state spouts with fixed ids.
Common situations: State spout id copied from a bolt id; transactional topologies declaring state spouts and spouts under the same id; builder reuse after a prior declaration.
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
- Bolt has already been declared for id
- 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/af9fa10f7ed9f5b4.
Report an issue: GitHub.
Appendix: source
Thrown at storm-core/src/jvm/backtype/storm/topology/TopologyBuilder.java:218
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;
}
private void initCommon(String id, IComponent component, Number parallelism) {
ComponentCommon common = new ComponentCommon();
common.set_inputs(new HashMap<GlobalStreamId, Grouping>());
if(parallelism!=null) common.set_parallelism_hint(parallelism.intValue());
Map conf = component.getComponentConfiguration();
if(conf!=null) common.set_json_conf(JSONValue.toJSONString(conf));View on GitHub (pinned to cdb116e942)