nathanmarz/storm · error · IllegalArgumentException

Spout has already been declared for id

Error message

Spout has already been declared for id ${id}

What it means

TopologyBuilder.validateUnusedId throws IllegalArgumentException when setSpout (or setBolt/setStateSpout) is called with an id that is already registered as a spout. Component ids must be globally unique in a Storm topology.

Solutions

  1. Rename the spout so its id is unique across bolts, spouts, and state spouts
  2. Use unique generated ids (e.g. "spout-" + name) when declaring multiple spouts
  3. Create a new TopologyBuilder instead of reusing a populated one
  4. Grep for duplicate setSpout calls with identical id strings

Example fix

// before
builder.setSpout("src", new KafkaSpout());
builder.setSpout("src", new TwitterSpout()); // throws
// after
builder.setSpout("kafka", new KafkaSpout());
builder.setSpout("twitter", new TwitterSpout());
Defensive patterns

Strategy: validation

Validate before calling

Set<String> used = new HashSet<>();
void safeSpout(TopologyBuilder b, String id, IRichSpout spout) {
    if (!used.add(id))
        throw new IllegalStateException("duplicate component id: " + id);
    b.setSpout(id, spout);
}

Try / catch

try {
    builder.setSpout(id, spout);
} catch (IllegalArgumentException e) {
    if (!e.getMessage().contains("already been declared")) throw e;
    // handle duplicate id
}

Prevention

When it happens

Trigger: Calling builder.setSpout(id, ...) with an id previously used for a spout; loops re-adding spouts with the same id; reusing a builder that already has the id registered.

Common situations: Multiple data sources declared with the same constant id like "spout"; copy-paste of a spout declaration where the id was not updated; programmatic topology generation with an off-by-one id counter.

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


AI-assisted analysis of nathanmarz/storm@cdb116e942 (2026-09-12). Data as JSON: /api/errors/ca69d8bec7788aed. Report an issue: GitHub.

Appendix: source

Thrown at storm-core/src/jvm/backtype/storm/topology/TopologyBuilder.java:215

        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;        
    }
    
    private void initCommon(String id, IComponent component, Number parallelism) {
        ComponentCommon common = new ComponentCommon();
        common.set_inputs(new HashMap<GlobalStreamId, Grouping>());

View on GitHub (pinned to cdb116e942)