nathanmarz/storm · error · IOException

unable to parse

Error message

unable to parse: ${string}

What it means

Thrown by ShellProcess.readMessage when a line read from the launched shell subprocess (for a non-JVM language driver) cannot be parsed as JSON via JSONValue.parse. It indicates the child process emitted malformed or unexpected output instead of a valid JSON message, often due to a crashed or misbehaving multilang process writing diagnostic text to stdout.

Solutions

  1. Inspect the offending string in the message; stray print/debug output from the shell component is the usual culprit.
  2. Ensure the multilang process writes only JSON messages (or end-of-stream markers) to stdout and sends diagnostics to stderr.
  3. Check that the shell component's serializer/protocol matches what Storm expects (JSON lines terminated with "end").
  4. Verify the subprocess did not crash or exit mid-conversation; check ShellProcess subprocess exit status and stderr logs.
Defensive patterns

Strategy: try-catch

When it happens

Trigger: Thrown at storm-core/src/jvm/backtype/storm/utils/ShellProcess.java:86 when the library encounters an invalid state.

Common situations: See trigger scenarios.

Understand the failure class


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

Appendix: source

Thrown at storm-core/src/jvm/backtype/storm/utils/ShellProcess.java:86

    public void writeMessage(Object msg) throws IOException {
        writeString(JSONValue.toJSONString(msg));
    }

    private void writeString(String str) throws IOException {
        byte[] strBytes = str.getBytes("UTF-8");
        processIn.write(strBytes, 0, strBytes.length);
        processIn.writeBytes("\nend\n");
        processIn.flush();
    }

    public JSONObject readMessage() throws IOException {
        String string = readString();
        JSONObject msg = (JSONObject)JSONValue.parse(string);
        if (msg != null) {
            return msg;
        } else {
            throw new IOException("unable to parse: " + string);
        }
    }

    public String getErrorsString() {
        if(processErrorStream!=null) {
            try {
                return IOUtils.toString(processErrorStream);
            } catch(IOException e) {
                return "(Unable to capture error stream)";
            }
        } else {
            return "";
        }
    }

    public void drainErrorStream()
    {
        try {

View on GitHub (pinned to cdb116e942)