karatelabs/karate · error · ParserException

'continue' may not cross a class static initialization block

Error message

'continue' may not cross a class static initialization block

What it means

Karate's embedded JS parser validates class static initialization block bodies against the ECMAScript grammar. A bare `continue` statement is only legal inside a loop, and a static block is not a loop; the check is skipped when the `continue` is nested inside a function or an enclosing loop (SB_FN / SB_LOOP flags). The parser throws this at parse time rather than producing silently invalid semantics.

Solutions

  1. Remove the bare `continue` from the static block top level — there is no loop to continue.
  2. Wrap the logic in a loop (for/while) inside the static block if iteration semantics are intended.
  3. Move the `continue` into a nested function only if the loop also lives inside that function; a `continue` cannot cross a function boundary either.
  4. If the intent was to skip static initialization, restructure with an `if` guard instead of `continue`.

Example fix

// before
class C {
  static {
    continue; // error
  }
}
// after
class C {
  static {
    for (const x of items) {
      if (skip(x)) continue; // legal: inside a loop
    }
  }
}
Defensive patterns

Strategy: validation

Validate before calling

// before evaluating a class body in Karate JS, scan for bare continue at static-block top level
function staticBlockHasBareContinue(src) {
  const m = src.match(/static\s*\{([\s\S]*?)\}/);
  return !!m && /(^|[^\w$.])continue\s*(;|\}|$)/.test(m[1]);
}
if (staticBlockHasBareContinue(src)) throw new Error('remove bare continue from static block');

Try / catch

try {
  const result = karate.eval(jsSource);
} catch (e) {
  if (String(e.message).includes("may not cross a class static initialization block")) {
    // fix the script source: strip/repair the static block statement
  } else throw e;
}

Prevention

When it happens

Trigger: Writing `class C { static { continue; } }` or any bare `continue` directly inside a `static { ... }` block that is not itself wrapped in a loop or function — e.g. `static { for(;;){} continue; }` at block top level. Evaluated when parsing Karate JS expressions or embedded JS scripts.

Common situations: Copy-pasting loop code into a static block during a refactor; porting code where a `continue`'s enclosing loop was removed or moved outside the static block; hand-writing class-based JS in Karate scenario expressions.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

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

                prev = type;
                continue;
            }
            prev = null;
            int childFlags = flags;
            switch (child.type) {
                case RETURN_STMT -> {
                    if ((flags & SB_FN) == 0) {
                        throw new ParserException("'return' is not allowed in a class static initialization block");
                    }
                }
                case BREAK_STMT -> {
                    if ((flags & (SB_FN | SB_LOOP | SB_SWITCH)) == 0 && child.size() == 1) {
                        throw new ParserException("'break' may not cross a class static initialization block");
                    }
                }
                case CONTINUE_STMT -> {
                    if ((flags & (SB_FN | SB_LOOP)) == 0 && child.size() == 1) {
                        throw new ParserException("'continue' may not cross a class static initialization block");
                    }
                }
                case FOR_STMT, WHILE_STMT, DO_WHILE_STMT -> childFlags |= SB_LOOP;
                case SWITCH_STMT -> childFlags |= SB_SWITCH;
                case FN_EXPR, FN_ARROW_EXPR -> childFlags |= SB_FN;
                default -> {
                }
            }
            // A function's parameters are [~Await] along with its body; an arrow's are
            // not — only the body (always its last child) leaves the reserved region.
            if (node.type == NodeType.FN_EXPR
                    || (node.type == NodeType.FN_ARROW_EXPR && i == last)) {
                childFlags |= SB_AWAIT_OK;
            }
            checkStaticBlockBody(child, childFlags);
        }
    }

View on GitHub (pinned to a22eb90246)