apache/cassandra · error · RuntimeException
Couldn't write stats html.
Error message
Couldn't write stats html.
What it means
StressGraph.generateGraph wraps IOExceptions from writing the final HTML report (opening the writer, writing, or closing) into a RuntimeException 'Couldn't write stats html.' It is thrown after substituting the computed stats block into the graph HTML template. The underlying IOException cause is dropped, hiding whether it was a permission issue, missing directory, or disk-full condition.
Solutions
- Check the output directory exists and is writable by the user running cassandra-stress.
- Free disk space or resolve quota/permission issues on the target filesystem.
- Write the report to a different, writable location and rerun the graph step.
- Patch the catch to include the target file and the cause: new RuntimeException("Couldn't write stats html: " + htmlFile, e).
Example fix
// before
catch (IOException e)
{
throw new RuntimeException("Couldn't write stats html.");
}
// after
catch (IOException e)
{
throw new RuntimeException("Couldn't write stats html: " + htmlFile, e);
} Defensive patterns
Strategy: validation
Validate before calling
java.io.File out = htmlFile; if (out == null || out.getParentFile() == null || !out.getParentFile().isDirectory() || !out.getParentFile().canWrite()) throw new IllegalArgumentException("Cannot write graph html to: " + out); Try / catch
try { generateGraph(); } catch (RuntimeException e) { if (e.getMessage().contains("Couldn't write stats html")) System.err.println("Check output dir permissions/disk space"); throw e; } Prevention
- Ensure the output directory exists and is writable by the stress process user.
- Monitor disk space/quota on machines producing reports.
- Avoid read-only mounts for graph output paths.
When it happens
Trigger: Calling generateGraph (via the stress graph option) when the output html file cannot be created or written: unwritable directory, read-only filesystem, invalid path, or an I/O error mid-write (out.write(html) / out.close()).
Common situations: Writing the graph into a directory that does not exist; running the stress tool as a user without write access to the output location; disk quota exceeded on CI machines; output path on a read-only mount.
Understand the failure class
Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.
Related errors
- Couldn't load existing stats html.
- Attempted skipBytes() on a closed RAR
- Attempted to seek in a closed RAR
- Ballot file corrupted
- Can't open %r for reading
AI-assisted analysis of apache/cassandra@88fd0f6a0e (2026-09-10).
Data as JSON: /api/errors/f5834e3767fd21e7.
Report an issue: GitHub.
Appendix: source
Thrown at tools/stress/src/org/apache/cassandra/stress/StressGraph.java:96
}
stats = this.createJSONStats(stats);
}
else
{
stats = this.createJSONStats(null);
}
try
{
PrintWriter out = new PrintWriter(htmlFile);
String statsBlock = "/* stats start */\nstats = " + JsonUtils.writeAsJsonString(stats) + ";\n/* stats end */\n";
String html = getGraphHTML().replaceFirst("/\\* stats start \\*/\n\n/\\* stats end \\*/\n", statsBlock);
out.write(html);
out.close();
}
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);
}
}
View on GitHub (pinned to 88fd0f6a0e)