karatelabs/karate · error · RuntimeException

image.write: failed to write

Error message

image.write: failed to write '{p}': {message}

What it means

writeBytes writes image bytes to the target path, creating parent directories as needed. Any failure in directory creation or file writing (permissions, missing filesystem, IO error) is wrapped in a RuntimeException identifying the path and underlying message.

Solutions

  1. Read the wrapped cause and path in the message; check whether the target directory exists and is writable
  2. Fix permissions on the report output directory (chmod/chown or fix the mount as read-write)
  3. Free disk space or raise the quota if the cause is no-space
  4. If overriding the path explicitly, pass a valid absolute path in a writable location

Example fix

// before
chmod 444 target/reports
karate.call('image.write', 'shot', bytes); // fails
// after
chmod 755 target/reports
karate.call('image.write', 'shot', bytes);
Defensive patterns

Strategy: try-catch

Validate before calling

# karate
* def outDir = karate.properties['karate.outputDir']
* if (!karate.os.path(outDir)) karate.call('mkoutputdir', outDir) // ensure writable dir exists

Try / catch

try { return karate.call('image.write', name, bytes); } catch (Exception e) { if (('' + e).startsWith('image.write: failed to write')) { karate.warn('write failed: ' + e.message); return null; } throw e; }

Prevention

When it happens

Trigger: Calling image.write (directly or via writeVerb) where the resolved target path's parent cannot be created or the file cannot be written — e.g. read-only report output dir, no space left on device, invalid path characters, or target inside a file (not directory).

Common situations: CI containers with a read-only workspace; report output dir deleted/replaced by a symlink mid-run; writing to /reports on a volume mounted read-only; disk quota exceeded on long suites; path containing illegal characters on Windows.

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


AI-assisted analysis of karatelabs/karate@a22eb90246 (2026-09-12). Data as JSON: /api/errors/a0232b6c6b35f521. Report an issue: GitHub.

Appendix: source

Thrown at karate-image/src/main/java/io/karatelabs/ext/image/ImageApi.java:469

    private boolean resourceExists(String p) {
        Resource r = resolveResource(p);
        return r != null && r.exists();
    }

    private void writeBytes(String p, byte[] bytes) {
        try {
            Resource r = resolveResource(p);
            java.nio.file.Path target = r != null ? r.getPath() : null;
            if (target == null) {
                target = new java.io.File(p).toPath();
            }
            java.nio.file.Path parent = target.getParent();
            if (parent != null) {
                java.nio.file.Files.createDirectories(parent);
            }
            java.nio.file.Files.write(target, bytes);
        } catch (Exception e) {
            throw new RuntimeException("image.write: failed to write '" + p + "': " + e.getMessage(), e);
        }
    }

    // ---- arg parsing + small helpers ----

    private static Map<String, Object> parseArgs(Object... args) {
        Map<String, Object> out = new LinkedHashMap<>();
        if (args.length == 1 && args[0] instanceof Map<?, ?> map) {
            map.forEach((k, v) -> out.put(String.valueOf(k), v));
            return out;
        }
        if (args.length > 0) {
            // a bare-name String → resolved baseline + <name> options; a path-looking String
            // (this:/classpath:/file:/contains a slash) → explicit baseline; bytes → baseline
            Object first = args[0];
            if (first instanceof String s && !looksLikePath(s)) {
                out.put("name", s);
            } else {

View on GitHub (pinned to a22eb90246)