{"record":{"id":"7f2fcaf530fc33c7","repo":"nathanmarz/storm","slug":"cannot-set-serializations-for-a-component-using-fluent-api","errorCode":null,"errorMessage":"Cannot set serializations for a component using fluent API","messagePattern":"Cannot set serializations for a component using fluent API","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"storm-core/src/jvm/backtype/storm/topology/TopologyBuilder.java","lineNumber":250,"sourceCode":"        ComponentCommon common = new ComponentCommon();\n        common.set_inputs(new HashMap<GlobalStreamId, Grouping>());\n        if(parallelism!=null) common.set_parallelism_hint(parallelism.intValue());\n        Map conf = component.getComponentConfiguration();\n        if(conf!=null) common.set_json_conf(JSONValue.toJSONString(conf));\n        _commons.put(id, common);\n    }\n\n    protected class ConfigGetter<T extends ComponentConfigurationDeclarer> extends BaseConfigurationDeclarer<T> {\n        String _id;\n        \n        public ConfigGetter(String id) {\n            _id = id;\n        }\n        \n        @Override\n        public T addConfigurations(Map conf) {\n            if(conf!=null && conf.containsKey(Config.TOPOLOGY_KRYO_REGISTER)) {\n                throw new IllegalArgumentException(\"Cannot set serializations for a component using fluent API\");\n            }\n            String currConf = _commons.get(_id).get_json_conf();\n            _commons.get(_id).set_json_conf(mergeIntoJson(parseJson(currConf), conf));\n            return (T) this;\n        }\n    }\n    \n    protected class SpoutGetter extends ConfigGetter<SpoutDeclarer> implements SpoutDeclarer {\n        public SpoutGetter(String id) {\n            super(id);\n        }        \n    }\n    \n    protected class BoltGetter extends ConfigGetter<BoltDeclarer> implements BoltDeclarer {\n        private String _boltId;\n\n        public BoltGetter(String boltId) {\n            super(boltId);","sourceCodeStart":232,"sourceCodeEnd":268,"githubUrl":"https://github.com/nathanmarz/storm/blob/cdb116e942666973bc4eaa0df098d5bab82739e7/storm-core/src/jvm/backtype/storm/topology/TopologyBuilder.java#L232-L268","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nbuilder.setBolt(\"split\", new SplitBolt())\n    .addConfigurations(kryoConf); // contains topology.kryo.register -> throws\n// after\nMap conf = new HashMap(kryoConf);\nconf.remove(Config.TOPOLOGY_KRYO_REGISTER);\nbuilder.setBolt(\"split\", new SplitBolt())\n    .addConfigurations(conf);\n// and register serializations topology-wide:\nstormConf.put(Config.TOPOLOGY_KRYO_REGISTER, kryoClasses);","handlingStrategy":"validation","validationCode":"if (conf != null && conf.containsKey(Config.TOPOLOGY_KRYO_REGISTER)) {\n    throw new IllegalArgumentException(\"Pass kryo registration at topology level, not per component\");\n}\ncomponentConf = new HashMap(conf);\ncomponentConf.remove(Config.TOPOLOGY_KRYO_REGISTER);","typeGuard":"boolean isComponentSafeConf(Map conf) {\n    return conf == null || !conf.containsKey(Config.TOPOLOGY_KRYO_REGISTER);\n}","tryCatchPattern":"try {\n    declarer.addConfigurations(conf);\n} catch (IllegalArgumentException e) {\n    LOG.warn(\"Kryo config rejected at component level; applying topology-wide\", e);\n    stormConf.put(Config.TOPOLOGY_KRYO_REGISTER, conf.get(Config.TOPOLOGY_KRYO_REGISTER));\n}","preventionTips":["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"],"tags":["storm","topology-builder","kryo","fluent-api","config"],"backgroundTag":"unsupported-operation","analyzedSha":"cdb116e942666973bc4eaa0df098d5bab82739e7","analyzedAt":"2026-09-12T14:30:00.714Z","contentChangedAt":"2026-09-12T14:30:00.714Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}