karatelabs/karate · warning
Failed to write feature HTML for
Error message
Failed to write feature HTML for {}: {} What it means
WARN log from HtmlReportListener.onFeatureEnd when rendering/copying the per-feature HTML report page throws. The feature's execution results are unaffected — only the per-feature HTML page for that feature fails to be written; the exception message is logged and swallowed.
Solutions
- Inspect the logged exception message to find the failing write and its path.
- Ensure the report output directory remains writable for the whole suite run.
- Verify disk space and that nothing (CI cleaner, antivirus) touches the output dir during the run.
- Confirm karate-core's report resources are intact in the jar/classpath (rebuild if corrupted).
Defensive patterns
Strategy: try-catch
Try / catch
// the listener already catches and logs; treat the log line as a report-completeness signal
if (logContains("Failed to write feature HTML")) {
verify(reportDir).resolve(expectedFeatureHtml).exists(); // re-generate if missing
} Prevention
- Keep the report output directory writable for the entire suite duration.
- Exclude the report dir from CI cleaners and antivirus scans during the run.
- Monitor disk space on long suites.
When it happens
Trigger: Exception in ensureResourcesCopied(), HtmlReportWriter.prepareFeatureData(), or renderFeatureHtml() — typically an I/O failure writing into the report output directory, or resource-copy failure (classpath assets unavailable, read-only output dir).
Common situations: Report output directory deleted or made read-only mid-run (e.g. CI cleaner); disk full during long suites; antivirus locking files on Windows; template resource missing from the classpath after packaging changes.
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
- Failed to create report directories
- Failed to write HTML summary
- Failed to copy static resources
- Failed to write HTML report
- inputFile: not a local file
AI-assisted analysis of karatelabs/karate@a22eb90246 (2026-09-12).
Data as JSON: /api/errors/0d14af7e6a48bcc1.
Report an issue: GitHub.
Appendix: source
Thrown at karate-core/src/main/java/io/karatelabs/output/HtmlReportListener.java:135
//
// Rendering used to be handed to a single-thread executor with an unbounded queue, on
// the reasoning that templating and IO should stay off the hot path. Measured, the
// opposite was true: rendering a feature page cost ~3x the suite's entire wall-clock
// when summed over all features, so that one thread could never keep up and its queue
// grew for the whole run — holding a complete page model per queued feature. Peak heap
// then tracked the number of features, not the number in flight. It was the single
// largest memory consumer with reports on, and it was noisy run-to-run because what
// was really being measured was a race between producer and writer.
//
// Inline, the cost is shared across every feature thread instead of serialized onto
// one, and a feature cannot complete until its page is on disk — so the page model is
// live for one feature per thread rather than for the whole suite.
try {
ensureResourcesCopied();
HtmlReportWriter.renderFeatureHtml(
HtmlReportWriter.prepareFeatureData(result, outputDir), outputDir, reportAssets);
} catch (Exception e) {
logger.warn("Failed to write feature HTML for {}: {}", result.getDisplayName(), e.getMessage());
}
}
/**
* A feature's result reduced to what the suite-end pages read.
*
* <p>Retaining {@code result.toJson()} whole is what made report generation the largest
* memory consumer in a long run: the map holds every step, its log text, its embeds and
* the full result tree of every {@code karate.call()} it made, and it stays reachable
* until the last feature finishes. Memory then scales with the size of the whole suite.
* Measured on a 60-calls-per-scenario shape, retention was roughly 1.5 MB per scenario
* with reports on against 0.43 MB with them off — reporting cost more than execution.
*
* <p>Neither consumer needs any of that. {@code buildFeatureSummaryList} and
* {@code buildTimelineData} read only feature-level identity and status plus a handful
* of per-scenario fields; {@code stepResults} is never touched at suite end. The
* per-feature HTML — the one thing that does need step detail — is written eagerly in
* {@link #onFeatureEnd} from the {@link FeatureResult} itself, before this reduction.View on GitHub (pinned to a22eb90246)