karatelabs/karate · warning
Failed to externalize embeds
Error message
Failed to externalize embeds: {} What it means
externalizeEmbeds() moves large embedded content (images, JSON attachments) out of the feature-result JSON into an embeds/ directory. Any IOException while writing those files is logged as a warning; the original JSON evidence stays inline, so data is not lost — only the lighter report layout is not achieved.
Solutions
- Check the output directory is writable and has free space before the run
- Reduce embed volume (smaller screenshots, truncate large bodies) if disk pressure is the cause
- Enable debug logging to capture the underlying IOException's full detail
- Re-run; since JSON stays inline, verify report completeness — this warning alone need not block the pipeline
Defensive patterns
Strategy: fallback
Validate before calling
Path embeds = outputDir.resolve("embeds");
if (!Files.isWritable(outputDir)) throw new IllegalStateException("output dir not writable: " + outputDir);
Files.createDirectories(embeds); // fail early, before the run Try / catch
try {
writeEmbedFiles(result, outputDir.resolve("embeds"));
} catch (IOException e) {
logger.warn("Failed to externalize embeds: {}", e.getMessage()); // JSON stays inline
} Prevention
- Ensure ample disk space where large embeds (screenshots, bodies) are expected
- Remember embeds remain inline in JSON on failure — validate report completeness, don't just check for the warning
- Pre-create the embeds directory in test setup
When it happens
Trigger: IOException from writeEmbedFiles(result, outputDir.resolve("embeds")) — e.g. the embeds directory cannot be created, a permission error, or disk full while writing embed payloads.
Common situations: Output directory on a full or read-only volume; embeds produced by large response bodies or many screenshots exhausting inodes/space; outputDir cleaned concurrently by another process.
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
- ext ' ': resource vanished after validation
- ext ' ': failed reading
- Failed to create session directory: " + directory
- Failed to backup existing dir
- Failed to copy static resources
AI-assisted analysis of karatelabs/karate@a22eb90246 (2026-09-12).
Data as JSON: /api/errors/8f78eeaf00aeb02b.
Report an issue: GitHub.
Appendix: source
Thrown at karate-core/src/main/java/io/karatelabs/output/HtmlReportWriter.java:269
Files.write(embedsDir.resolve(fileName), part.getData());
part.setFileName(fileName);
}
}
/**
* Externalize a feature result's inline-bytes embeds to {@code <outputDir>/embeds/} and set each
* part's {@code fileName}, so EVERY downstream serializer — the JSONL event stream <em>and</em> the
* HTML data JSON — references the file rather than inlining base64 (large screenshots stay on disk,
* the report still works off a folder / {@code file://}). Called from the {@code FEATURE_EXIT} seam
* ({@code Suite.fireEvent}) before any listener serializes the result; idempotent (a part with a
* fileName is skipped), so the HTML writer's later pass numbers each embed exactly once. Best-effort
* — a write failure never breaks the run. JSON evidence stays inline (see {@link #writeEmbedFile}).
*/
public static void externalizeEmbeds(FeatureResult result, Path outputDir) {
try {
writeEmbedFiles(result, outputDir.resolve("embeds"));
} catch (IOException e) {
logger.warn("Failed to externalize embeds: {}", e.getMessage());
}
}
/**
* Write embed files to the embeds/ directory.
* Sets the fileName on each Embed for JSON serialization.
*/
private static void writeEmbedFiles(FeatureResult result, Path embedsDir) throws IOException {
if (!hasEmbeds(result)) {
return; // No embeds to write
}
Files.createDirectories(embedsDir);
for (ScenarioResult sr : result.getScenarioResults()) {
// @report=false scenarios suppress all step detail in toJson(); skip
// embed extraction so screenshots / attachments don't leak to disk either.
if (sr.isReportDisabled()) continue;
for (StepResult step : sr.getStepResults()) {View on GitHub (pinned to a22eb90246)