karatelabs/karate · error · RuntimeException

image: unsupported image value

Error message

image: unsupported image value {className} (expected a Uint8Array, byte[], or a path string)

What it means

toBytes() normalizes any image argument (latest, baseline) into raw bytes. It accepts a Uint8Array (via JsValue), a Java byte[], or a String treated as a file path. Any other type (Number, Map, JSON object, boolean, etc.) is rejected with this error, because the API cannot interpret it as image content.

Solutions

  1. Pass the image as a path string, e.g. image.diff({ baseline: 'base.png', latest: 'shot.png' })
  2. If you have bytes, pass the actual byte[]/Uint8Array, not a wrapper object
  3. Unwrap the value: if it is a JSON object, extract the byte field before calling diff
  4. Check that the JS variable is not undefined-object; log its type before the call

Example fix

// before
const img = { data: karate.readBytes('shot.png') }
image.diff({ latest: img }) // unsupported: Map
// after
image.diff({ latest: karate.readBytes('shot.png') })
Defensive patterns

Strategy: type-guard

Validate before calling

// JS: ensure the value is a string path or byte-like before diff
if (typeof latest !== 'string' && !(latest instanceof Array) && !latest.byteLength) {
    karate.fail('latest must be a path string or bytes, got: ' + typeof latest);
}

Type guard

function isImageValue(o) {
  return typeof o === 'string'
      || (o instanceof Uint8Array)
      || (Array.isArray(o)); // byte[] via JS array
}

Prevention

When it happens

Trigger: Passing a value of unsupported type as an image argument: a JS object/JSON map, a number, a Response object, a base64 string not prefixed as a path, or the result of a step that returned an object instead of bytes/path.

Common situations: Storing image bytes in a JSON variable and passing the whole JSON instead of the byte field; passing a JS Number read from a file; accidentally passing the options map as the image argument; migrating tests where the previous API accepted base64 strings directly.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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

Appendix: source

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

            throw new RuntimeException("image.diff: 'latest' image (bytes or path) is required");
        }
        return latest;
    }

    private byte[] toBytes(Object o) {
        if (o == null) {
            return null;
        }
        if (o instanceof byte[] b) {
            return b;
        }
        if (o instanceof io.karatelabs.js.JsValue jv) {
            return toBytes(jv.getJavaValue());
        }
        if (o instanceof String s) {
            return readBytes(s);
        }
        throw new RuntimeException("image: unsupported image value " + o.getClass().getName()
                + " (expected a Uint8Array, byte[], or a path string)");
    }

    /** A base64 {@code data:} URL for raw image bytes (mime sniffed; for client-side re-diff). */
    private static String dataUrl(byte[] b) {
        return "data:" + sniffMime(b) + ";base64," + java.util.Base64.getEncoder().encodeToString(b);
    }

    private static String sniffMime(byte[] b) {
        if (b != null && b.length >= 4) {
            int b0 = b[0] & 0xFF, b1 = b[1] & 0xFF, b2 = b[2] & 0xFF, b3 = b[3] & 0xFF;
            if (b0 == 0x89 && b1 == 'P' && b2 == 'N' && b3 == 'G') return "image/png";
            if (b0 == 0xFF && b1 == 0xD8 && b2 == 0xFF) return "image/jpeg";
            if (b0 == 'G' && b1 == 'I' && b2 == 'F' && b3 == '8') return "image/gif";
            if (b0 == 'B' && b1 == 'M') return "image/bmp";
        }
        return "image/png";
    }

View on GitHub (pinned to a22eb90246)