karatelabs/karate · error · JsErrorException (typeError)
cannot set property on null 'super' base
Error message
cannot set property on null 'super' base
What it means
In `super.prop = value` assignments, if the superclass lookup finds the home object's [[Prototype]] is null, there is no base object to write to. The engine deliberately raises this TypeError only after the RHS is evaluated (matching PutValue ordering) rather than treating it as a scope update.
Solutions
- Restore the class's prototype chain so [[Prototype]] is not null.
- Avoid `setPrototypeOf(..., null)` on classes using `super` property writes.
- Replace `super.x = v` with an explicit write to the intended parent object when exotic hierarchies are in play.
Example fix
// before Object.setPrototypeOf(Derived.prototype, null); // super.x = 1 now throws // after Object.setPrototypeOf(Derived.prototype, Base.prototype);
Defensive patterns
Strategy: validation
Validate before calling
// ensure the class prototype chain is intact before using super writes
if (Object.getPrototypeOf(Derived.prototype) === null) throw new Error('Derived has null prototype; super writes will fail'); Type guard
function hasSuperBase(C) { return Object.getPrototypeOf(C.prototype) !== null; } Try / catch
try { instance.step(); } catch (e) { if (String(e.message).includes("null 'super' base")) { restorePrototype(instance.constructor); } else { throw e; } } Prevention
- Never setPrototypeOf(..., null) on classes that use super.
- Preserve prototype chains in class factories and frameworks.
- Prefer composition over manual prototype surgery when super writes are involved.
When it happens
Trigger: A derived class method executes `super.x = v` while the class's home object has a null prototype (e.g. `Object.setPrototypeOf(cls.prototype, null)` or a class created without a proper prototype chain).
Common situations: Manual prototype surgery that nulls the parent; classes built via exotic factories without correct prototypes; framework code that resets prototype chains.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- cannot create property
- AggregateError requires an iterable of errors
- Array.from requires an iterable or array-like object, not
- Array.prototype.* called on null or undefined
- BigInt.prototype method called on non-BigInt
AI-assisted analysis of karatelabs/karate@a22eb90246 (2026-09-12).
Data as JSON: /api/errors/b1ce4a524cc6d536.
Report an issue: GitHub.
Appendix: source
Thrown at karate-js/src/main/java/io/karatelabs/js/PropertyAccess.java:336
// Same slot-or-name routing as set(): a scope-confined let/const
// is reachable only through its stamped slot — it has no byName
// entry, so a name-keyed update would miss it and fall through to
// an outer binding or an implicit global.
set(node, context, value, trackingNode);
yield value;
}
case REF_DOT_EXPR, REF_BRACKET_EXPR -> {
AccessSite site = resolveWriteSite(node, context);
if (context.isStopped()) yield Terms.UNDEFINED;
Object value = Interpreter.eval(rhsNode, context);
if (site == null || site == SHORT_CIRCUIT_SITE || context.isStopped()) yield value;
if (site.target == null && node.getFirst().type == NodeType.SUPER_EXPR) {
// A super reference whose home object has a null [[Prototype]]
// resolves to a null base; PutValue on it is a TypeError —
// AFTER the RHS has been evaluated (hence not in
// resolveWriteSite). Without this, setByName's null-target
// fallback would treat the write as a scope update.
throw JsErrorException.typeError("cannot set property on null 'super' base");
}
if (site.privateName != null) PrivateAccess.set(site.target, site.privateName, value, context);
else siteWrite(site, value, context, trackingNode);
yield value;
}
default -> throw JsErrorException.typeError("cannot set on: " + node);
};
}
/**
* Compound assignment (`op=`, e.g. +=, -=, *=) in spec §13.15 order:
* resolve the LHS Reference, GetValue it, and only then evaluate the RHS —
* a computed-key or getter side effect precedes any RHS side effect, and
* an abrupt completion at each step skips the rest. Returns the new value.
*/
static Object compound(Node node, CoreContext context, TokenType operator, Node rhsNode, Node trackingNode) {
return switch (node.type) {
case REF_EXPR -> {View on GitHub (pinned to a22eb90246)