karatelabs/karate · error · RuntimeException

embed(): each part needs a 'role'

Error message

embed(): each part needs a 'role'

What it means

Validation in toMultiPartEmbed, the map-form of embed(): every entry in the 'parts' list must carry a 'role' key so the multipart body part can be classified (e.g. form-field vs file). Fires when a part object omits 'role'; add a role to each part.

Solutions

  1. Add a role string to every part object: {role: 'screenshot', path: 'a.png'}.
  2. Ensure the role value is not JS null/undefined at build time.
  3. Keep roles descriptive and consistent across steps for readable reports.

Example fix

// before
karate.embed({ parts: [{ path: 'a.png' }] });

// after
karate.embed({ parts: [{ role: 'screenshot', path: 'a.png' }] });
Defensive patterns

Strategy: validation

Validate before calling

if (parts.some(function(p){ return p == null || p.role == null; })) { throw new Error('each part needs a role'); }

Type guard

function hasRole(p) { return p != null && typeof p === 'object' && typeof p.role === 'string' && p.role.length > 0; }

Try / catch

try { karate.embed({ parts: parts }); } catch (e) { if (String(e.message).includes("needs a 'role'")) { karate.log('part missing role'); } throw e; }

Prevention

When it happens

Trigger: karate.embed({parts: [{path: 'a.png'}]}) or parts objects built dynamically where role was omitted or set to null.

Common situations: Hand-writing embed payloads and forgetting role; dynamic part construction where the role variable was undefined; migrating single embeds to multipart form without adding roles.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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

Appendix: source

Thrown at karate-core/src/main/java/io/karatelabs/core/KarateJsBase.java:530

                    ? 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) {
                bytes = readPathBytes(pathObj.toString());
            } else {
                throw new RuntimeException("embed(): part '" + role + "' needs 'data', 'path', or 'url'");
            }

View on GitHub (pinned to a22eb90246)