nathanmarz/storm · error · RuntimeException

Must submit topologies using the 'storm' client script so…

Error message

Must submit topologies using the 'storm' client script so that StormSubmitter knows which jar to upload.

What it means

submitJar requires the localJar path to be non-null; the 'storm' client script sets it so StormSubmitter knows which jar to upload to Nimbus. Running the topology's main class directly (e.g. `java -cp ... Main`) leaves localJar null, so a RuntimeException is thrown.

Solutions

  1. Submit via the storm client: `storm jar mytopology.jar com.mypack.MyTopology <name>`.
  2. If you must launch with java, set the jar path yourself and call StormSubmitter.submitJar(conf, localJar) explicitly.
  3. For IDEs, create a run configuration that mimics the storm script or use local mode (LocalCluster) instead.
  4. Guard the code: only call submitTopology when running under the storm script.

Example fix

// before
StormSubmitter.submitTopology(name, conf, topology); // run via plain java
// after - guard
if (System.getProperty("storm.jar") == null) {
    throw new IllegalStateException("Run with: storm jar app.jar ...");
}
StormSubmitter.submitTopology(name, conf, topology);
Defensive patterns

Strategy: validation

Validate before calling

// ensure we're running under 'storm jar' before submitting
if (System.getProperty("storm.jar") == null) {
    throw new IllegalStateException("Use: storm jar <jar> <mainClass> ...");
}

Try / catch

try {
    StormSubmitter.submitTopology(name, conf, topology);
} catch (RuntimeException e) {
    if (e.getMessage() != null && e.getMessage().contains("'storm' client script")) {
        log.error("Re-run via: storm jar app.jar " + Main.class.getName());
    } else { throw e; }
}

Prevention

When it happens

Trigger: Running the topology main class with plain `java` instead of the `storm jar` wrapper; calling StormSubmitter.submitTopology from a context where the jar path was never injected; running from an IDE without the storm client script.

Common situations: IDE run configurations launching topology main directly; local tests accidentally calling submitTopology; docs examples copied without using the storm CLI.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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

Appendix: source

Thrown at storm-core/src/jvm/backtype/storm/StormSubmitter.java:148

            client.close();
        }
    }

    private static String submittedJar = null;
    
    private static void submitJar(Map conf) {
        if(submittedJar==null) {
            LOG.info("Jar not uploaded to master yet. Submitting jar...");
            String localJar = System.getProperty("storm.jar");
            submittedJar = submitJar(conf, localJar);
        } else {
            LOG.info("Jar already uploaded to master. Not submitting jar.");
        }
    }
    
    public static String submitJar(Map conf, String localJar) {
        if(localJar==null) {
            throw new RuntimeException("Must submit topologies using the 'storm' client script so that StormSubmitter knows which jar to upload.");
        }
        NimbusClient client = NimbusClient.getConfiguredClient(conf);
        try {
            String uploadLocation = client.getClient().beginFileUpload();
            LOG.info("Uploading topology jar " + localJar + " to assigned location: " + uploadLocation);
            BufferFileInputStream is = new BufferFileInputStream(localJar);
            while(true) {
                byte[] toSubmit = is.read();
                if(toSubmit.length==0) break;
                client.getClient().uploadChunk(uploadLocation, ByteBuffer.wrap(toSubmit));
            }
            client.getClient().finishFileUpload(uploadLocation);
            LOG.info("Successfully uploaded topology jar to assigned location: " + uploadLocation);
            return uploadLocation;
        } catch(Exception e) {
            throw new RuntimeException(e);            
        } finally {
            client.close();

View on GitHub (pinned to cdb116e942)