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
- Pass the image as a path string, e.g. image.diff({ baseline: 'base.png', latest: 'shot.png' })
- If you have bytes, pass the actual byte[]/Uint8Array, not a wrapper object
- Unwrap the value: if it is a JSON object, extract the byte field before calling diff
- 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
- Pass image args only as path strings, byte[], or Uint8Array
- Never pass JSON maps/Response objects directly as images
- Unwrap nested objects to the raw bytes field before calling the API
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
- set() with a single argument expects a Map / JSON object
- assert expression must return boolean:
- baseline image is not a valid image
- body() needs at least one argument
- boot.ext(' '): does not implement io.karatelabs.core.Ext
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)