karatelabs/karate · error · JsErrorException
is not defined
Error message
${varName} is not defined What it means
Thrown as a ReferenceError when an identifier cannot be resolved through any binding frame — no local slot, closure, or global carries the name. `evalRefExprByName` calls context.resolve and, if it returns null, reports the variable as undefined.
Solutions
- Fix the variable-name spelling or declare the variable before use (var/let/const).
- Pass required values into embedded JS via the available context (e.g. karate.get / function arguments).
- Verify the host object or global you expect is actually registered with the Karate JS engine in this scope.
Example fix
// before var total = price * qty; // price never defined // after var price = 10; var total = price * qty;
Defensive patterns
Strategy: try-catch
Validate before calling
if (typeof price === 'undefined') throw new Error('price must be defined before use'); Type guard
function isDefined(v) { return typeof v !== 'undefined'; } Try / catch
try { total = price * qty; } catch (e) { if (String(e).includes('is not defined')) { price = karate.get('price'); total = price * qty; } } Prevention
- Declare every variable before use
- Check spelling/case of identifiers
- Pass cross-feature values explicitly, don't rely on scope leakage
When it happens
Trigger: Reading an undeclared identifier in Karate JS: typo in a variable name, using a variable defined in another feature/JS scope without passing it, or referencing a host object not registered in the engine context.
Common situations: Calling shared JS utilities that expect injected variables (karate, config values) which were not provided; misspelling camelCase names; assuming variables from one scenario leak into another.
Related errors
- is not defined
- ReferenceError: ' ' is not defined — did you mean `_. `?…
- cannot access ' ' before initialization
- is not defined
- Unable to resolve global `this`
AI-assisted analysis of karatelabs/karate@a22eb90246 (2026-09-12).
Data as JSON: /api/errors/4dd3c09e4cde3f9d.
Report an issue: GitHub.
Appendix: source
Thrown at karate-js/src/main/java/io/karatelabs/js/Interpreter.java:2609
// The name-keyed tail of evalRefExpr, outlined so the slot fast path above
// stays small enough to inline reliably — an at-threshold hot method here
// flips whole benchmark rows run to run depending on JIT timing.
private static Object evalRefExprByName(Node node, CoreContext context) {
String varName = node.getText();
if ("this".equals(varName)) {
return context.getThisObject();
}
if (context.callArgs != null && "arguments".equals(varName)) {
JsArray a = context.argumentsForRead();
if (a != null) {
return a;
}
// arrow frame with no enclosing function — ordinary resolution
}
BindingSlot s = context.resolve(varName);
if (s == null) {
throw JsErrorException.referenceError(varName + " is not defined");
}
return context.readSlot(s, varName);
}
private static Object evalReturnStmt(Node node, CoreContext context) {
if (node.size() > 1) {
Object value = eval(node.get(1), context);
// `return somethingThatThrew()` — a callee that threw has already propagated its throw
// onto THIS context (JsFunctionNode.bindArgsAndExecute), and stopAndReturn would clear
// it and complete the function normally. The throw then no longer exists anywhere: a
// surrounding try/catch never fires, and the host-call boundary sees a clean return.
// Leave the context in its error state and let the exit unwind carry it.
if (context.isError()) {
return value;
}
return context.stopAndReturn(value);
} else {
// a valueless `return` completes with undefined, not null — the two areView on GitHub (pinned to a22eb90246)