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
- Remove the bare `continue` from the static block top level — there is no loop to continue.
- Wrap the logic in a loop (for/while) inside the static block if iteration semantics are intended.
- Move the `continue` into a nested function only if the loop also lives inside that function; a `continue` cannot cross a function boundary either.
- 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
- Never place break/continue at the top level of a static block.
- Keep loop control statements inside the loop they control.
- Prefer simple, side-effect-light static blocks; extract loops into functions.
- Lint generated JS before passing it to karate.eval.
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
- parser state: [ ]
- optional chain is not a valid assignment target
- unary expression cannot be the base of '**'; wrap it in…
- optional chain cannot be the operand of postfix ++/--
- optional chain cannot be the operand of prefix ++/--
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)