nathanmarz/storm · error · IllegalArgumentException

Fields for already set

Error message

Fields for ${streamId} already set

What it means

OutputFieldsGetter tracks declared streams in _fields; declareStream throws IllegalArgumentException if the same streamId is declared twice. Storm requires each stream id on a component to be declared exactly once. This is a topology-definition (user code) error thrown at topology declaration time.

Solutions

  1. Declare each stream id only once per component; remove the duplicate declareStream call
  2. If the default stream is declared via declare(), do not also call declareStream("default", ...)
  3. Use unique stream ids (e.g. prefix with component-specific names)
  4. Check for a shared/reused OutputFieldsDeclarer instance and create a fresh one per component

Example fix

// before
declarer.declareStream("default", new Fields("a"));
declarer.declareStream("default", new Fields("b")); // throws
// after
declarer.declareStream("default", new Fields("a"));
declarer.declareStream("secondary", new Fields("b"));
Defensive patterns

Strategy: validation

Validate before calling

Set<String> declared = new HashSet<>();
void safeDeclare(OutputFieldsDeclarer d, String streamId, Fields f) {
    if (!declared.add(streamId))
        throw new IllegalStateException("duplicate stream: " + streamId);
    d.declareStream(streamId, f);
}

Try / catch

try {
    declarer.declareStream(streamId, fields);
} catch (IllegalArgumentException e) {
    if (!e.getMessage().contains("already set")) throw e;
    // log and skip duplicate declaration
}

Prevention

When it happens

Trigger: Calling declareStream twice with the same streamId; calling declare() on a component that also already used declareStream("default", ...) for the default stream; an OutputFieldsDeclarer shared/reused across two components (e.g. a cached getter) so ids collide.

Common situations: Dynamic/stream-id built from variables that accidentally repeats; a base class declares the default stream and the subclass declares it again; reusing one OutputFieldsGetter object for multiple components in a builder helper.

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/4c33b48ec00501c5. Report an issue: GitHub.

Appendix: source

Thrown at storm-core/src/jvm/backtype/storm/topology/OutputFieldsGetter.java:43

public class OutputFieldsGetter implements OutputFieldsDeclarer {
    private Map<String, StreamInfo> _fields = new HashMap<String, StreamInfo>();

    public void declare(Fields fields) {
        declare(false, fields);
    }

    public void declare(boolean direct, Fields fields) {
        declareStream(Utils.DEFAULT_STREAM_ID, direct, fields);
    }

    public void declareStream(String streamId, Fields fields) {
        declareStream(streamId, false, fields);
    }

    public void declareStream(String streamId, boolean direct, Fields fields) {
        if(_fields.containsKey(streamId)) {
            throw new IllegalArgumentException("Fields for " + streamId + " already set");
        }
        _fields.put(streamId, new StreamInfo(fields.toList(), direct));
    }


    public Map<String, StreamInfo> getFieldsDeclaration() {
        return _fields;
    }

}

View on GitHub (pinned to cdb116e942)