karatelabs/karate · error · RuntimeException

cannot replace root path $

Error message

cannot replace root path $

What it means

Json.setInternal() implements Json.set()/setAsString(); replacing the entire root ($, i.e. the whole document) is not supported because the document context was built around the existing root value. Callers must instead mutate paths inside the document.

Solutions

  1. Set child paths instead, e.g. set("$.field", value)
  2. Build a new Json from the desired value via Json.of(newMap) and use that object
  3. Use document mutation helpers or re-create the Json wrapper

Example fix

// before
json.set("$", newMap);
// after
json.set("$.field", newMap.get("field")); // or: json = Json.of(newMap);
Defensive patterns

Strategy: validation

Validate before calling

if ("$".equals(path) || path == null) { throw new IllegalArgumentException("set() cannot replace root; use Json.of() to build a new document"); }

Try / catch

try { json.set(path, value); } catch (RuntimeException e) { if ("cannot replace root path $".equals(e.getMessage())) { json = Json.of(value); } else { throw e; } }

Prevention

When it happens

Trigger: json.set("$", newMap) or json.set("$", value), or setAsString("$", jsonText) — targeting the root path.

Common situations: Wanting to wholesale-replace a parsed document's content; porting code that assumed set('$') acts like assignment.

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/28c2e9ad034e24be. Report an issue: GitHub.

Appendix: source

Thrown at karate-core/src/main/java/io/karatelabs/common/Json.java:305

        if (leftPos == -1) {
            return -1;
        }
        int rightPos = s.indexOf(']', leftPos);
        String num = s.substring(leftPos + 1, rightPos);
        if (num.isEmpty()) {
            return -1;
        }
        try {
            return Integer.parseInt(num);
        } catch (NumberFormatException e) {
            return -1;
        }
    }

    private void setInternal(String path, Object o) {
        path = prefix(path);
        if ("$".equals(path)) {
            throw new RuntimeException("cannot replace root path $");
        }
        boolean forArray = isArrayPath(path);
        if (!pathExists(path)) {
            createPath(path, forArray);
        }
        Pair<String> pair = toParentAndLeaf(path);
        if (forArray) {
            int index = arrayIndex(pair.right);
            if (index == -1) {
                doc.add(arrayKey(path), o);
            } else {
                doc.set(path, o);
            }
        } else {
            doc.put(pair.left, pair.right, o);
        }
    }

View on GitHub (pinned to a22eb90246)