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
- Remove the Config.TOPOLOGY_KRYO_REGISTER key from the map before passing it to addConfigurations
- 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(...))
- 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
- Never merge whole worker/storm configs into per-component configs without stripping topology.* keys
- Keep kryo registrations exclusively in the topology-level submission config
- Sanitize shared config maps once in a helper before feeding the fluent API
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
- Unable to create serializer
- Could not instantiate a class listed in config under section
- Blowfish encryption key not specified
- Blowfish encryption key invalid
- Don't know how to convert
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)