karatelabs/karate · error · JsErrorException (typeError)

' ' was defined without a setter

Error message

'${pn.name}' was defined without a setter

What it means

When writing a private accessor via `PrivateAccess.set`, the engine found the private name declared as an accessor with only a getter (no setter). Assigning to a getter-only private accessor is a TypeError per the ES spec.

Solutions

  1. Add a setter to the accessor declaration.
  2. Remove or redirect the assignment if the member is intentionally read-only.
  3. Convert the member to a plain private field `#prop` if direct writes are acceptable.
  4. Write to an underlying private field that the getter reads instead.

Example fix

// before
class C { get #x() { return 1; } }
new C().#x = 2; // TypeError: '#x' was defined without a setter
// after
class C { #x = 1; } // or add: set #x(v) { ... }
Defensive patterns

Strategy: validation

Validate before calling

// verify a setter exists before assigning to a private accessor
const hasSetter = /set\s+#prop\b|accessor\s+#prop\b/.test(classSource);

Type guard

function privateAccessorWritable(classSrc, name) { return new RegExp('(set\\s+#' + name + '|accessor\\s+#' + name + ')').test(classSrc); }

Try / catch

try { obj.#prop = v; } catch (e) { if (e instanceof TypeError && e.message.includes('without a setter')) { /* write underlying field instead */ } else { throw e; } }

Prevention

When it happens

Trigger: Assigning `obj.#prop = value` where the class declared `accessor #prop` (or an accessor pair) without a `set` accessor.

Common situations: Read-only private accessors assigned from subclass or internal code; a refactor that dropped the setter while write sites remained; confusing plain private fields (which accept writes) with accessors (which do not).

Understand the failure class

Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.

Related errors


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

Appendix: source

Thrown at karate-js/src/main/java/io/karatelabs/js/PrivateAccess.java:71

            case FIELD -> obj.getPrivate(pn);
            case METHOD -> pn.method;
            case ACCESSOR -> {
                if (pn.getter == null) {
                    throw JsErrorException.typeError("'" + pn.name + "' was defined without a getter");
                }
                yield Interpreter.invokeGetter(pn.getter, target, context);
            }
        };
    }

    static void set(Object target, PrivateName pn, Object value, CoreContext context) {
        JsObject obj = branded(target, pn, "write");
        switch (pn.kind) {
            case FIELD -> obj.putPrivate(pn, value);
            case METHOD -> throw JsErrorException.typeError("Cannot write to private method " + pn.name);
            case ACCESSOR -> {
                if (pn.setter == null) {
                    throw JsErrorException.typeError("'" + pn.name + "' was defined without a setter");
                }
                Interpreter.invokeSetter(pn.setter, target, value, context);
            }
        }
    }

    private static JsObject branded(Object target, PrivateName pn, String verb) {
        if (target instanceof JsObject obj && obj.hasPrivate(pn)) {
            return obj;
        }
        throw JsErrorException.typeError("Cannot " + verb + " private member " + pn.name
                + " from an object whose class did not declare it");
    }

}

View on GitHub (pinned to a22eb90246)