karatelabs/karate · error · ParserException

invalid destructuring: rest element cannot have an…

Error message

invalid destructuring: rest element cannot have an initializer

What it means

The Karate JS parser rejects a rest element in array destructuring that carries a default value, e.g. `[...rest = []] = arr`. The spec forbids initializers on rest elements because the rest binding always receives an array (possibly empty) and can never be undefined. Detected statically via restHasInitializer on the last ARRAY_ELEM.

Solutions

  1. Remove the `= default` from the rest element: `[a, ...rest]`
  2. Assign the fallback after destructuring: `rest = rest || []` (though rest is always an array)
  3. If a default is genuinely needed, destructure into a plain binding instead of a rest element

Example fix

// before
const [a, ...rest = []] = arr;
// after
const [a, ...rest] = arr;
Defensive patterns

Strategy: validation

Validate before calling

// flag rest elements with initializers
if (/\.\.\.\s*[A-Za-z_$][\w$]*\s*=/.test(src)) {
  throw new Error('script has a rest element with an initializer');
}

Try / catch

try {
  runScript(src);
} catch (e) {
  if (String(e).includes('rest element cannot have an initializer')) {
    // strip the = default from the rest element
  }
  throw e;
}

Prevention

When it happens

Trigger: Parsing patterns like `[a, ...rest = []] = arr;` — hasRestPrefix identifies the rest element and restHasInitializer finds an `=` default after it.

Common situations: Copy-paste where a normal element's default was left on the rest element; defensive coding habits of adding defaults everywhere applied to `...rest` where it is meaningless.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


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

Appendix: source

Thrown at karate-js/src/main/java/io/karatelabs/parser/JsParser.java:1539

     * a spread {@code [...arr, b]} in a regular array literal stays valid.
     */
    private static void validateRestElementRules(Node litArray) {
        int lastArrayElemIdx = -1;
        for (int i = 0, n = litArray.size(); i < n; i++) {
            Node ch = litArray.get(i);
            if (!ch.isToken() && ch.type == NodeType.ARRAY_ELEM) {
                lastArrayElemIdx = i;
            }
        }
        for (int i = 0, n = litArray.size(); i < n; i++) {
            Node ch = litArray.get(i);
            if (ch.isToken() || ch.type != NodeType.ARRAY_ELEM) continue;
            if (!hasRestPrefix(ch)) continue;
            if (i != lastArrayElemIdx) {
                throw new ParserException("invalid destructuring: rest element must be the last binding element");
            }
            if (restHasInitializer(ch)) {
                throw new ParserException("invalid destructuring: rest element cannot have an initializer");
            }
        }
    }

    private static boolean hasRestPrefix(Node arrayElem) {
        if (arrayElem.size() == 0) return false;
        Node first = arrayElem.getFirst();
        return first.isToken() && first.token.type == DOT_DOT_DOT;
    }

    /**
     * For an ARRAY_ELEM that starts with {@code ...}, returns true iff the target
     * expression after the DOT_DOT_DOT carries a top-level assignment — i.e. the
     * rest target is being given a default value, which is invalid.
     */
    private static boolean restHasInitializer(Node arrayElem) {
        boolean sawDot = false;
        for (int i = 0, n = arrayElem.size(); i < n; i++) {

View on GitHub (pinned to a22eb90246)