apache/cassandra · error · RuntimeException

Couldn't parser stats json

Error message

Couldn't parser stats json: %s

What it means

StressGraph.parseExistingStats extracts the embedded 'stats = {...};' JSON from an existing graph HTML and parses it with Jackson's readTree; a parse failure (malformed or missing JSON) is rethrown as RuntimeException "Couldn't parser stats json: <message>". This indicates the previous report HTML was truncated, hand-edited, or generated by an incompatible version whose stats block format differs.

Solutions

  1. Open the HTML and check the content between '/* stats start */' and '/* stats end */' is valid JSON ending in ';'.
  2. Regenerate the graph from the original stress log instead of loading the corrupted HTML.
  3. Use matching versions of the stress tool for generating and re-graphing reports.
  4. Keep the cause in the thrown exception (already present: e) and include the source file in the message for diagnosability.

Example fix

// before
throw new RuntimeException("Couldn't parser stats json: "+e.getMessage(), e);
// after
throw new RuntimeException("Couldn't parse stats json from existing html: " + e.getMessage(), e);
Defensive patterns

Strategy: try-catch

Validate before calling

String html = new String(Files.readAllBytes(htmlPath), StandardCharsets.UTF_8); if (!html.contains("/* stats start */") || !html.contains("/* stats end */")) throw new IllegalStateException("No valid stats block in existing html; regenerate the graph");

Try / catch

try { graph.generate(); } catch (RuntimeException e) { if (e.getMessage() != null && e.getMessage().startsWith("Couldn't parser stats json")) { System.err.println("Existing report corrupt; regenerating from log"); graph.generateFromLog(); } else throw e; }

Prevention

When it happens

Trigger: generateGraph loads an existing HTML file whose /* stats start */ ... /* stats end */ block either does not match the regex (empty/absent group(1)) or contains invalid JSON, causing IOException from JSON_OBJECT_MAPPER.readTree(matcher.group(1)).

Common situations: A previous stress run was killed mid-write leaving a truncated stats block; the HTML was manually edited; upgrading cassandra-stress across versions changed the JSON schema; copying the HTML through a tool that mangled the embedded script.

Understand the failure class

Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.

Related errors


AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10). Data as JSON: /api/errors/4ba886f51e78dd23. Report an issue: GitHub.

Appendix: source

Thrown at tools/stress/src/org/apache/cassandra/stress/StressGraph.java:111

        }
        catch (IOException e)
        {
            throw new RuntimeException("Couldn't write stats html.");
        }
    }

    private ObjectNode parseExistingStats(String html)
    {
        Pattern pattern = Pattern.compile("(?s).*/\\* stats start \\*/\\nstats = (.*);\\n/\\* stats end \\*/.*");
        Matcher matcher = pattern.matcher(html);
        matcher.matches();
        try
        {
            return (ObjectNode) JsonUtils.JSON_OBJECT_MAPPER.readTree(matcher.group(1));
        }
        catch (IOException e)
        {
            throw new RuntimeException("Couldn't parser stats json: "+e.getMessage(), e);
        }
    }

    private String getGraphHTML()
    {
        try (InputStream graphHTMLRes = StressGraph.class.getClassLoader().getResourceAsStream("org/apache/cassandra/stress/graph/graph.html"))
        {
            return new String(ByteStreams.toByteArray(graphHTMLRes));
        }
        catch (IOException e)
        {
            throw new RuntimeException(e);
        }
    }

    /** Parse log and append to stats array */
    private ArrayNode parseLogStats(InputStream log, ArrayNode stats) {
        BufferedReader reader = new BufferedReader(new InputStreamReader(log));

View on GitHub (pinned to 88fd0f6a0e)