karatelabs/karate · error · JsErrorException

cannot set . (on )

Error message

cannot set . (on )

What it means

Thrown by JavaUtils.setStatic when a JS script attempts to assign to a static field of a Java class and the reflective write fails for any reason: field doesn't exist, isn't public, is final, or the value type is incompatible. Reported as 'cannot set .<name> (on <TypeName>)'.

Solutions

  1. Confirm the field is a public, non-final, static, mutable field of the exact class.
  2. Convert the assigned value to the field's declared type (e.g. java.lang.Integer.valueOf(42)).
  3. Prefer setter methods or configuration APIs over direct static field mutation.
  4. For final fields, redesign — they cannot be legally reassigned via set().

Example fix

// before
var System = Java.type('java.lang.System');
System.out = null; // final field, fails
// after
var System = Java.type('java.lang.System');
System.setProperty('my.key', 'value');
Defensive patterns

Strategy: validation

Validate before calling

var f = Clz.getClass().getField('fieldName');
var ok = java.lang.reflect.Modifier.isStatic(f.getModifiers()) && !java.lang.reflect.Modifier.isFinal(f.getModifiers()) && java.lang.reflect.Modifier.isPublic(f.getModifiers());
if (!ok) karate.fail('field is not a public non-final static');

Try / catch

try { Clz.field = value; } catch (e) { if (String(e).indexOf('cannot set') !== -1) { Clz.setField(value); } else { throw e; } }

Prevention

When it happens

Trigger: ClassName.someField = value where someField is not a public non-final static field, or where the assigned JS value cannot be stored in the field's declared type.

Common situations: Trying to mutate JDK constants (Integer.MAX_VALUE), assigning to final or system properties fields, type mismatches (string into an int field), and JPMS-restricted fields.

Related errors


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

Appendix: source

Thrown at karate-js/src/main/java/io/karatelabs/js/JavaUtils.java:157

        return method;
    }

    private static Method findStaticMethod(Class<?> clazz, String name) {
        for (Method method : clazz.getMethods()) {
            if (method.getName().equals(name) && Modifier.isStatic(method.getModifiers())
                    && method.getParameterCount() == 0) {
                return method;
            }
        }
        return null;
    }

    static void setStatic(Class<?> clazz, String name, Object value) {
        try {
            Field field = clazz.getField(name);
            field.set(null, value);
        } catch (Exception e) {
            throw JsErrorException.typeError("cannot set ." + name + " (on " + jsTypeName(clazz) + ")");
        }
    }

    /**
     * Returned by {@link #getOrNotFound} when a Java object has no member of that name — the
     * <em>expected</em> outcome of a JS property read that misses, which is why it is a value
     * and not an exception. Never escapes into JS: the one caller
     * ({@code PropertyAccess.accessViaBridge}) turns it into {@code undefined}.
     */
    static final Object NOT_FOUND = new Object();

    /** A member that is a method, not a getter or field — resolved to a callable on read. */
    private static final Object METHOD_MARKER = new Object();

    /**
     * Per-class resolution of a property name to the getter / field / method that serves it,
     * or {@link #NOT_FOUND}. Every entry here — the misses above all — used to be recomputed on
     * every read, and computing one costs up to three {@code Class.getMethods()} array copies

View on GitHub (pinned to a22eb90246)