nathanmarz/storm · error · IllegalArgumentException
Storm conf is not valid. Must be json-serializable
Error message
Storm conf is not valid. Must be json-serializable
What it means
StormSubmitter.submitTopology validates the stormConf Map with Utils.isValidConf, which requires every value to be JSON-serializable. If the conf contains non-serializable objects (custom classes, nulls in wrong places, etc.), it throws this IllegalArgumentException before contacting Nimbus.
Solutions
- Replace non-serializable values in stormConf with JSON primitives (String, Number, Boolean, Map, List).
- Call Utils.isValidConf(conf) yourself before submitting to catch the bad key early.
- If you need complex objects in a bolt, pass them via component configuration alternatives or serialize them yourself.
- Print/inspect the conf Map and check each value's type.
Example fix
// before
conf.put("my.custom.object", new MyConfigBean());
// after
conf.put("my.custom.object", myBean.toJsonString()); Defensive patterns
Strategy: try-catch
Validate before calling
// call before submitTopology
if (!Utils.isValidConf(myConf)) {
for (Map.Entry e : ((Map) myConf).entrySet()) {
try { new Gson().toJsonTree(e.getValue()); }
catch (Exception ex) { System.err.println("Non-serializable conf value at key: " + e.getKey()); }
}
} Try / catch
try {
StormSubmitter.submitTopology(name, conf, topology);
} catch (IllegalArgumentException e) {
if (e.getMessage().contains("json-serializable")) {
log.error("Conf has non-JSON-serializable values; sanitize conf", e);
} else { throw e; }
} Prevention
- Restrict conf values to String/Number/Boolean/Map/List.
- Never pass domain objects in topology conf; serialize them to strings.
- Validate conf in CI with Utils.isValidConf.
When it happens
Trigger: Putting non-JSON-serializable values into the topology conf Map (e.g. arbitrary Java objects, streams, complex types) and calling StormSubmitter.submitTopology / submitTopologyWithProgressBar.
Common situations: Programmatically building conf with typed objects (Date, custom config beans); reading conf from code that mixes Object values; injecting per-topology settings that aren't primitives/collections.
Understand the failure class
Background: "JSON serialization failed", "not JSON serializable", "Failed to serialize": why JSON marshaling errors happen and how to fix them — this error's family across 46 libraries.
Related errors
AI-assisted analysis of nathanmarz/storm@cdb116e942 (2026-09-12).
Data as JSON: /api/errors/b8e79dae57a8b235.
Report an issue: GitHub.
Appendix: source
Thrown at storm-core/src/jvm/backtype/storm/StormSubmitter.java:75
public static void submitTopology(String name, Map stormConf, StormTopology topology) throws AlreadyAliveException, InvalidTopologyException {
submitTopology(name, stormConf, topology, null);
}
/**
* Submits a topology to run on the cluster. A topology runs forever or until
* explicitly killed.
*
*
* @param name the name of the storm.
* @param stormConf the topology-specific configuration. See {@link Config}.
* @param topology the processing to execute.
* @param options to manipulate the starting of the topology
* @throws AlreadyAliveException if a topology with this name is already running
* @throws InvalidTopologyException if an invalid topology was submitted
*/
public static void submitTopology(String name, Map stormConf, StormTopology topology, SubmitOptions opts) throws AlreadyAliveException, InvalidTopologyException {
if(!Utils.isValidConf(stormConf)) {
throw new IllegalArgumentException("Storm conf is not valid. Must be json-serializable");
}
stormConf = new HashMap(stormConf);
stormConf.putAll(Utils.readCommandLineOpts());
Map conf = Utils.readStormConfig();
conf.putAll(stormConf);
try {
String serConf = JSONValue.toJSONString(stormConf);
if(localNimbus!=null) {
LOG.info("Submitting topology " + name + " in local mode");
localNimbus.submitTopology(name, null, serConf, topology);
} else {
NimbusClient client = NimbusClient.getConfiguredClient(conf);
if(topologyNameExists(conf, name)) {
throw new RuntimeException("Topology with name `" + name + "` already exists on cluster");
}
submitJar(conf);
try {
LOG.info("Submitting topology " + name + " in distributed mode with conf " + serConf);View on GitHub (pinned to cdb116e942)