karatelabs/karate · error · java.lang.RuntimeException

expression

Error message

expression: <expr> - <cause message>

What it means

When evaluating a property/index access chain, PropertyAccess catches an underlying evaluation failure and, if it cannot resolve a bridge/type for the base object, rethrows as "expression: <expr> - <cause message>". It wraps the original cause, so the real failure (unknown variable, bad method, null base) is in the chained exception.

Solutions

  1. Read the chained cause message to find the real failure (undefined variable, missing method, etc.).
  2. Assert/validate the variable exists before the expression: use karate.match or a JS typeof/null check.
  3. Fix the typo or ensure the upstream step that produces the base object actually ran and set the value.

Example fix

// before (Karate script)
* def x = response.data.items[0].name // expression: response.data.items[0].name - ... if data missing
// after
* assert response.data != null
* def items = response.data.items || []
* def x = items.length ? items[0].name : null
Defensive patterns

Strategy: validation

Validate before calling

// Karate script: validate base values before member access
* assert response != null && response.data != null
* def items = response.data ? (response.data.items || []) : []

Type guard

// JS in Karate
function safeGet(obj, path) {
  return path.split('.').reduce((o, k) => (o == null ? undefined : o[k]), obj);
}

Try / catch

try {
    value = karate.eval(expression);
} catch (RuntimeException e) {
    if (e.getMessage().startsWith("expression:")) {
        logger.warn("failed expression: {} cause: {}", expression, e.getCause());
        value = null; // or default
    } else throw e;
}

Prevention

When it happens

Trigger: A dot/bracket access chain where an intermediate evaluation throws and the base object cannot be determined — e.g. referencing an undefined variable then calling a member (x.foo() with x undefined), or an expression on a null/unknown context value.

Common situations: Typos in Karate script variables, accessing members of a response field that does not exist, calling Java interop methods on undefined values, schema/config keys not set before the expression runs.

Related errors


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

Appendix: source

Thrown at karate-js/src/main/java/io/karatelabs/js/PropertyAccess.java:735

                object = Interpreter.eval(node.getFirst(), context);
            } catch (Exception e) {
                if (context.root.bridge != null) {
                    String base = node.getFirst().getText();
                    String path = base + "." + name;
                    ExternalAccess ja = context.root.bridge.forType(path);
                    if (ja != null) {
                        if (wantReceiver) context.callReceiver = null;
                        if (functionCall) {
                            return (JsConstructor) (c, args) -> ja.construct(args);
                        }
                        return ja;
                    }
                    object = context.root.bridge.forType(base);
                } else {
                    object = null;
                }
                if (object == null) {
                    throw new RuntimeException("expression: " + node.getFirst().getText() + " - " + e.getMessage(), e);
                }
            }
            // Propagate short-circuit from a deeper ?. step.
            if (object == SHORT_CIRCUITED) return SHORT_CIRCUITED;
            // Local ?. fires here.
            if (optional && (object == null || object == Terms.UNDEFINED)) return SHORT_CIRCUITED;
        } else {
            optional = true;
            if (node.get(1).type == NodeType.REF_BRACKET_EXPR) {
                object = Interpreter.eval(node.getFirst(), context);
                if (object == SHORT_CIRCUITED) return SHORT_CIRCUITED;
                // ?.[expr] fires here — index is not evaluated when short-circuiting.
                if (object == null || object == Terms.UNDEFINED) return SHORT_CIRCUITED;
                Object index = Interpreter.eval(node.get(1).get(2), context);
                Object v = getByIndex(object, index, false, context, functionCall);
                if (wantReceiver) context.callReceiver = object;
                return v;
            } else {

View on GitHub (pinned to a22eb90246)