karatelabs/karate · error · RuntimeException
embed(): each 'parts' entry must be an object
Error message
embed(): each 'parts' entry must be an object
What it means
When karate.embed() receives a multipart embed object ({parts: [...]}), every entry of the parts list must itself be an object describing a part (role, data/path/url, optional mime). Karate throws this when a parts entry is a string, number, array, or null instead of a map.
Solutions
- Wrap each entry as an object: karate.embed({parts: [{role: 'screenshot', path: 'shot.png'}]}).
- Validate each part object has a role plus one of data/path/url before calling embed.
- If embedding a single item, pass the bytes directly instead of a parts list.
Example fix
// before
karate.embed({ parts: ['shot.png'] });
// after
karate.embed({ parts: [{ role: 'image', path: 'shot.png' }] }); Defensive patterns
Strategy: validation
Validate before calling
if (parts.some(function(p){ return p == null || typeof p !== 'object' || Array.isArray(p); })) { throw new Error('each part must be an object'); } Type guard
function isEmbedPart(p) { return p != null && typeof p === 'object' && !Array.isArray(p); } Try / catch
try { karate.embed({ parts: parts }); } catch (e) { if (String(e.message).includes("each 'parts' entry must be an object")) { karate.log('invalid parts entry'); } throw e; } Prevention
- Wrap file paths in part objects instead of passing raw strings
- Validate the parts array shape before calling embed
- Prefer single-content embed (bytes) when multipart structure is not needed
When it happens
Trigger: karate.embed({ name: ..., parts: ['screenshot.png'] }) or parts entries that are plain strings / null / nested lists instead of objects with role and content fields.
Common situations: Assuming parts can be plain file paths; building the parts list programmatically and pushing raw paths; JSON structures where entries ended up as strings after templating.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- embed(): each part needs a 'role'
- embed(): part ' ' needs 'data', 'path', or 'url
- embed() needs at least one argument: data
- doc() called, but no destination set
- read() needs at least one argument
AI-assisted analysis of karatelabs/karate@a22eb90246 (2026-09-12).
Data as JSON: /api/errors/e915146f71c85bbb.
Report an issue: GitHub.
Appendix: source
Thrown at karate-core/src/main/java/io/karatelabs/core/KarateJsBase.java:526
return null;
}
// single-part (legacy)
String mimeType = args.length > 1 && args[1] != null
? args[1].toString() : KarateJsUtils.detectMimeType(first);
String name = args.length > 2 ? args[2].toString() : null;
byte[] data = KarateJsUtils.convertToBytes(first);
LogContext.get().embed(data, mimeType, name);
return null;
};
}
private StepResult.Embed toMultiPartEmbed(Map<?, ?> map) {
String name = map.get("name") != null ? map.get("name").toString() : null;
List<StepResult.Part> parts = new ArrayList<>();
for (Object partObj : (List<?>) map.get("parts")) {
Object pu = unwrapJs(partObj);
if (!(pu instanceof Map<?, ?> pm)) {
throw new RuntimeException("embed(): each 'parts' entry must be an object");
}
Object roleObj = pm.get("role");
if (roleObj == null) {
throw new RuntimeException("embed(): each part needs a 'role'");
}
String role = roleObj.toString();
String mime = pm.get("mime") != null ? pm.get("mime").toString() : null;
Object url = pm.get("url");
if (url != null) {
parts.add(new StepResult.Part(role, mime, url.toString()));
continue;
}
byte[] bytes;
Object dataObj = pm.get("data");
Object pathObj = pm.get("path");
if (dataObj != null) {
bytes = KarateJsUtils.convertToBytes(unwrapJs(dataObj));
} else if (pathObj != null) {View on GitHub (pinned to a22eb90246)