karatelabs/karate · error · ParserException

invalid destructuring: rest element must be the last…

Error message

invalid destructuring: rest element must be the last binding element

What it means

The Karate JS parser rejects array destructuring patterns where a rest element (`...rest`) is followed by more binding elements. Per spec, `...` must be the final element of an array destructuring pattern. This is a static early error on the literal's parsed ARRAY_ELEM nodes.

Solutions

  1. Move the `...rest` element to the final position: `[a, b, ...rest]`
  2. Split the destructuring into multiple statements if you need elements after collecting the rest (e.g. `rest[0]`)
  3. Remove the rest element if you only need fixed-position bindings

Example fix

// before
const [...rest, last] = arr;
// after
const [init, ...rest] = arr;
const last = rest[rest.length - 1];
Defensive patterns

Strategy: validation

Validate before calling

// reject patterns where ...rest is not last in an array destructuring
function restNotLast(src) {
  const m = src.match(/\[([^\]]*)\]\s*=/);
  if (!m) return false;
  const parts = m[1].split(',').map(s => s.trim()).filter(Boolean);
  const restIdx = parts.findIndex(p => /^\.\.\./.test(p));
  return restIdx !== -1 && restIdx !== parts.length - 1;
}

Try / catch

try {
  runScript(src);
} catch (e) {
  if (String(e).includes('rest element must be the last')) {
    // reorder destructuring elements
  }
  throw e;
}

Prevention

When it happens

Trigger: Parsing patterns like `[...rest, a] = arr;` or `const [...head, tail] = list;` — the loop flags any rest-prefixed ARRAY_ELEM whose index is not the last array element index.

Common situations: Typos where the rest element was typed first; refactoring that reordered destructuring elements; misunderstanding that rest collects 'the remainder' and must come last.

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/915721b3f8e678d4. Report an issue: GitHub.

Appendix: source

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

     *       AssignmentExpression).</li>
     * </ul>
     * Called only when the surrounding {@code LIT_ARRAY} is in pattern context;
     * 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.
     */

View on GitHub (pinned to a22eb90246)