nathanmarz/storm · error · IllegalArgumentException

Cannot set serializations for a component using fluent API

Error message

Cannot set serializations for a component using fluent API

What it means

TopologyBuilder's fluent API (setBolt/setSpout declarers) refuses to let you attach per-component Kafka-style serialization config. Kryo serializations must be registered once at the topology level, not per component, so passing a config map containing 'topology.kryo.register' to addConfigurations throws IllegalArgumentException immediately.

Solutions

  1. Remove the Config.TOPOLOGY_KRYO_REGISTER key from the map before passing it to addConfigurations
  2. Register Kryo classes once on the whole topology instead: conf.put(Config.TOPOLOGY_KRYO_REGISTER, ...) and pass conf to StormSubmitter.submitTopology (or use topology.registerSerialization(...))
  3. Use addConfiguration(key, value) only for non-kryo per-component keys

Example fix

// before
builder.setBolt("split", new SplitBolt())
    .addConfigurations(kryoConf); // contains topology.kryo.register -> throws
// after
Map conf = new HashMap(kryoConf);
conf.remove(Config.TOPOLOGY_KRYO_REGISTER);
builder.setBolt("split", new SplitBolt())
    .addConfigurations(conf);
// and register serializations topology-wide:
stormConf.put(Config.TOPOLOGY_KRYO_REGISTER, kryoClasses);
Defensive patterns

Strategy: validation

Validate before calling

if (conf != null && conf.containsKey(Config.TOPOLOGY_KRYO_REGISTER)) {
    throw new IllegalArgumentException("Pass kryo registration at topology level, not per component");
}
componentConf = new HashMap(conf);
componentConf.remove(Config.TOPOLOGY_KRYO_REGISTER);

Type guard

boolean isComponentSafeConf(Map conf) {
    return conf == null || !conf.containsKey(Config.TOPOLOGY_KRYO_REGISTER);
}

Try / catch

try {
    declarer.addConfigurations(conf);
} catch (IllegalArgumentException e) {
    LOG.warn("Kryo config rejected at component level; applying topology-wide", e);
    stormConf.put(Config.TOPOLOGY_KRYO_REGISTER, conf.get(Config.TOPOLOGY_KRYO_REGISTER));
}

Prevention

When it happens

Trigger: Calling addConfigurations(Map) on the ComponentConfigurationDeclarer returned by setBolt()/setSpout() with a map that contains Config.TOPOLOGY_KRYO_REGISTER ("topology.kryo.register") as a key.

Common situations: Migrating from the old non-fluent API where component conf maps could embed kryo registrations; copying a shared conf map (e.g. whole worker config) into a bolt's component config without stripping the kryo key; programmatic topology generation that merges global config into every component.

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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

Appendix: source

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

        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));
        _commons.put(id, common);
    }

    protected class ConfigGetter<T extends ComponentConfigurationDeclarer> extends BaseConfigurationDeclarer<T> {
        String _id;
        
        public ConfigGetter(String id) {
            _id = id;
        }
        
        @Override
        public T addConfigurations(Map conf) {
            if(conf!=null && conf.containsKey(Config.TOPOLOGY_KRYO_REGISTER)) {
                throw new IllegalArgumentException("Cannot set serializations for a component using fluent API");
            }
            String currConf = _commons.get(_id).get_json_conf();
            _commons.get(_id).set_json_conf(mergeIntoJson(parseJson(currConf), conf));
            return (T) this;
        }
    }
    
    protected class SpoutGetter extends ConfigGetter<SpoutDeclarer> implements SpoutDeclarer {
        public SpoutGetter(String id) {
            super(id);
        }        
    }
    
    protected class BoltGetter extends ConfigGetter<BoltDeclarer> implements BoltDeclarer {
        private String _boltId;

        public BoltGetter(String boltId) {
            super(boltId);

View on GitHub (pinned to cdb116e942)