karatelabs/karate · error · RuntimeException

karate.call() arg must be a map or list, got

Error message

karate.call() arg must be a map or list, got: <class>

What it means

karate.call() accepts an optional second argument that must be a Map (or null) for a single call, or a List to loop-call. When a single (non-list) call is given any other type — string, number, boolean, function — this RuntimeException is thrown naming the offending Java class.

Solutions

  1. Wrap scalar arguments in a map: karate.call('path.feature', { id: myId }).
  2. If you intend per-element calls, pass a JS array (List) instead of a single object.
  3. Parse JSON strings before passing: JSON.parse(str) or karate.read of a .json file.
  4. Call the function first and pass its result, not the function reference itself.

Example fix

// before
* def result = karate.call('classpath:user.feature', userId)

// after
* def result = karate.call('classpath:user.feature', { userId: '#(userId)' })
Defensive patterns

Strategy: validation

Validate before calling

// before calling
var arg = karate.get('payload');
if (arg != null && !(arg instanceof Map) && !Array.isArray(arg)) {
    karate.log('normalizing arg to map:', typeof arg);
    arg = { value: arg };
}
var result = karate.call('classpath:user.feature', arg);

Type guard

function isCallArg(a) {
  return a == null || a instanceof Map || Array.isArray(a);
}
if (!isCallArg(payload)) payload = { value: payload };

Try / catch

try {
    var result = karate.call('classpath:user.feature', payload);
} catch (e) {
    if (String(e).indexOf('arg must be a map or list') >= 0) {
        result = karate.call('classpath:user.feature', { value: payload });
    } else { throw e; }
}

Prevention

When it happens

Trigger: karate.call('path.feature', arg) where arg is a JS primitive (e.g. a string id), a function, or any non-Map non-List value; passing a JSON string instead of a parsed object.

Common situations: Passing a single scalar instead of wrapping it in an object; reading JSON from a file as text and passing it without parsing; a JS function reference typed where its result was intended.

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/e0310d39c9adbb16. Report an issue: GitHub.

Appendix: source

Thrown at karate-core/src/main/java/io/karatelabs/core/ScenarioRuntime.java:619

                }
                // Non-callable JS (e.g. an object/JSON literal file) — return as-is.
                return jsTarget;
            }
            calledFeature = Feature.read(calledResource);
        }

        // Array-loop call - delegate to shared helper used by the `call` keyword
        if (arg instanceof List) {
            return executor.callFeatureLoop(calledFeature, (List<?>) arg, tagSelector, lineFilters);
        }

        // Single call - arg must be a map (or null)
        Map<String, Object> callArg = null;
        if (arg != null) {
            if (arg instanceof Map) {
                callArg = (Map<String, Object>) arg;
            } else {
                throw new RuntimeException("karate.call() arg must be a map or list, got: " + arg.getClass());
            }
        }

        Map<String, Object> resultVars = executor.callFeatureSingle(calledFeature, callArg, tagSelector, lineFilters);
        return resultVars != null ? resultVars : new HashMap<>();
    }

    /**
     * Execute karate.callonce() - runs a feature once per FeatureRuntime and caches the result.
     * Uses the same cache as the callonce keyword.
     * Uses double-check locking to ensure thread-safe execution in parallel scenarios.
     */
    public Object executeJsCallOnce(String path, Object arg) {
        if (featureRuntime == null) {
            throw new RuntimeException("karate.callonce() requires a feature context");
        }

        // Use the same cache key format as the keyword: "callonce:call read('path')"

View on GitHub (pinned to a22eb90246)