karatelabs/karate · error · JsErrorException
called on null or undefined
Error message
called on null or undefined
What it means
Karate's JS engine implements the ECMAScript spec preamble for Object.keys/values/entries: they require a coercible object. Calling any of them with null, undefined, or no argument throws a TypeError instead of returning an empty result, matching test262 behavior.
Solutions
- Check the value is non-null before calling Object.keys/values/entries: `if (val) Object.keys(val)`.
- Use a default: `Object.keys(val || {})`.
- Fix upstream logic so the variable is defined before this call (e.g. define it in karate-config.js or guard with karate.get).
Example fix
// before
var names = Object.keys(response.body.user);
// after
var names = Object.keys(response.body.user || {}); Defensive patterns
Strategy: type-guard
Validate before calling
function isCoercibleObject(v) { return v != null; }
if (!isCoercibleObject(val)) throw new Error('expected object for Object.keys'); Type guard
function isObjectLike(v) { return v !== null && typeof v === 'object'; } Try / catch
try { var keys = Object.keys(val); } catch (e) { if (String(e).indexOf('called on null or undefined') !== -1) { var keys = []; } else { throw e; } } Prevention
- Default optional objects with `|| {}` before introspection
- Define Karate variables before use (karate-config.js or Background)
- Check API response fields exist before iterating them
When it happens
Trigger: Object.keys(null), Object.values(undefined), Object.entries() with no args, or any of these called on a variable that resolved to null/undefined at runtime (e.g. a missing JSON response field).
Common situations: Iterating over an API response field that is absent; a Karate variable not yet defined; a function that returns null on failure being passed straight into Object.keys.
Related errors
- argumentsList must be an iterable object
- assignment to constant
- assignment to constant
- Cannot add property , object is not extensible
- Cannot add property , object is not extensible
AI-assisted analysis of karatelabs/karate@a22eb90246 (2026-09-12).
Data as JSON: /api/errors/419757c61e5815f7.
Report an issue: GitHub.
Appendix: source
Thrown at karate-js/src/main/java/io/karatelabs/js/JsObjectConstructor.java:218
private Object entries(Context context, Object[] args) {
requireObjectCoercible(args, "Object.entries");
CoreContext cc = context instanceof CoreContext c ? c : null;
List<Object> result = new ArrayList<>();
for (KeyValue kv : Terms.toIterable(args[0], cc)) {
List<Object> entry = new ArrayList<>();
entry.add(kv.key());
entry.add(kv.value());
result.add(new JsArray(entry));
}
return new JsArray(result);
}
/** Spec ToObject preamble: Object.keys/values/entries throw TypeError on
* null/undefined ahead of any iteration (test262
* Object/keys/15.2.3.14-1-4 and -1-5). */
private static void requireObjectCoercible(Object[] args, String op) {
if (args.length < 1 || args[0] == null || args[0] == Terms.UNDEFINED) {
throw JsErrorException.typeError(op + " called on null or undefined");
}
}
private Object assign(Context context, Object[] args) {
if (args.length == 0) {
return new LinkedHashMap<>();
}
if (args[0] == null || args[0] == Terms.UNDEFINED) {
throw JsErrorException.typeError("Cannot convert undefined or null to object");
}
CoreContext cc = context instanceof CoreContext c ? c : null;
// §20.1.2.1: the target itself is mutated and returned — identity is
// observable (`Object.assign(t, src) === t`), and step 4c is
// Set(to, key, value, true), so target setters fire and a rejected
// write throws. Spread/rest keep CreateDataProperty semantics via
// Terms.copyDataProperties; the two operations are not the same seam.
// ToObject approximation for a primitive target: no mutable wrapper
// exists, so copy into a fresh map that stands in for the wrapper —View on GitHub (pinned to a22eb90246)