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

  1. Rename one of the bolts so every component id is unique
  2. Generate ids programmatically (e.g. "bolt-" + index) to avoid collisions
  3. Use a fresh TopologyBuilder for each topology build instead of reusing one
  4. 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

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


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)