karatelabs/karate · warning

karate.properties is read-only, ignoring write of

Error message

karate.properties is read-only, ignoring write of '{}' — use System.setProperty() or Runner.Builder.systemProperty() to set one

What it means

In Karate, the karate.properties map exposed to scripts is a read-only view over system properties. Writes via karate.put/putAll are no-ops: the map logs this warning telling the developer the write was ignored and to use System.setProperty() or Runner.Builder.systemProperty() instead. Scripts still read properties normally.

Solutions

  1. Use System.setProperty('key','value') (or in a feature: karate.setSystemProperty) to set a JVM system property
  2. Use Runner.Builder.systemProperty("key","value") to set properties at runner construction time
  3. Use karate.set('name', value) / scenario variables to share values within Karate instead of the properties map
  4. Remove the write entirely if the property was only meant for the same script (a variable suffices)

Example fix

// before (ignored, warns)
* karate.properties.put('my.flag', 'true')
// after
* karate.setSystemProperty('my.flag', 'true')
Defensive patterns

Strategy: type-guard

Validate before calling

// detect a read-only properties view before writing
java.util.Map<String,String> props = karate.getProperties();
try { props.put("probe", "probe"); props.remove("probe"); System.out.println("writable"); }
catch (UnsupportedOperationException e) { System.out.println("read-only: use karate.setSystemProperty"); }

Type guard

function propertiesAreWritable(){ try { karate.properties.__probe = 1; delete karate.properties.__probe; return true; } catch(e){ return false; } }

Prevention

When it happens

Trigger: A feature or JS calls karate.properties.put('key','value') (or putAll) at runtime, or a script mutates the properties map returned from karate.properties.

Common situations: Porting old scripts that relied on writable karate.properties; tests trying to pass configuration to downstream code by writing a property mid-run; shared utilities that mutate properties instead of using karate.set / variables.

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/9d8e1cc213024623. Report an issue: GitHub.

Appendix: source

Thrown at karate-core/src/main/java/io/karatelabs/core/Suite.java:1290

        }

        @Override
        public boolean containsKey(Object key) {
            if (overrides != null && overrides.containsKey(key)) {
                return true;
            }
            return key instanceof String name && System.getProperty(name) != null;
        }

        /**
         * {@code karate.properties['x'] = 'y'} has never set anything: it used to land in a
         * throwaway copy and vanish. Kept a no-op rather than made to throw — a script doing it
         * would start failing — but it is worth one line saying the write went nowhere, since
         * silently losing it is how someone spends an afternoon.
         */
        @Override
        public String put(String key, String value) {
            logger.warn("karate.properties is read-only, ignoring write of '{}'"
                    + " — use System.setProperty() or Runner.Builder.systemProperty() to set one", key);
            return get(key);
        }

        @Override
        public Set<Entry<String, String>> entrySet() {
            Map<String, String> merged = new HashMap<>();
            System.getProperties().forEach((k, v) -> merged.put(k.toString(), v.toString()));
            if (overrides != null) {
                merged.putAll(overrides);
            }
            return merged.entrySet();
        }
    }

    public DriverProvider getDriverProvider() {
        return driverProvider;
    }

View on GitHub (pinned to a22eb90246)