karatelabs/karate · error · ParserException
label already in scope
Error message
label already in scope: ${name} What it means
A statement label must be unique within its scope; re-declaring the same label in nested (non-function) code is a static error. labelNodeChecks maintains a linked Label chain and rejects a LABELLED_STMT whose name already appears in the chain. Function bodies, arrow functions, and class static blocks reset the chain (labels outside are invisible, so re-use there is fine).
Solutions
- Rename the inner (or outer) label to a unique name
- Move the inner labeled statement into its own function, which resets label scope
- Remove the redundant inner label if `break`/`continue` there can target the outer label legally
Example fix
// before
outer: for (;;) { outer: for (;;) { break outer; } }
// after
outer: for (;;) { inner: for (;;) { break inner; } } Defensive patterns
Strategy: validation
Validate before calling
// Collect labels and flag re-declarations within one function scope:
const labels = [...src.matchAll(/([A-Za-z_$][\w$]*):\s*(?:for|while|do|\{|switch|if)/g)].map(m=>m[1]);
const dup = labels.filter((l,i)=>labels.indexOf(l)!==i); Try / catch
try { eval(js); } catch (e) { if (String(e).includes('label already in scope')) { /* rename the inner label */ } throw e; } Prevention
- Give nested loops distinct, descriptive label names
- Extract nested labeled code into functions to reset label scope
- Avoid reusing generic labels like `loop`/`outer` across nested blocks
When it happens
Trigger: Writing `outer: ... outer: ...` where the second `outer` is nested within the first's statement (not separated by a function boundary) — Label.contains(labels, name, false) finds the prior binding.
Common situations: Copy-pasted loop blocks each carrying the same label inside one function; wrapping existing labeled code in another labeled block; template-generated loops reusing label names.
Related errors
- private name is not declared in an enclosing class
- break references an undefined label
- continue references an undefined label
- continue label does not name a loop
- unexpected logical-assignment operator
AI-assisted analysis of karatelabs/karate@a22eb90246 (2026-09-12).
Data as JSON: /api/errors/414e47402a668523.
Report an issue: GitHub.
Appendix: source
Thrown at karate-js/src/main/java/io/karatelabs/parser/JsParser.java:403
}
return false;
}
}
/**
* §14.13.1 label early errors at a single node (no recursion — {@link #earlyErrors}
* drives the traversal): a label may not be nested inside a statement already carrying
* it, {@code break} / {@code continue} may only name an enclosing label, and
* {@code continue} additionally needs that label to name an iteration statement.
* Returns the label chain visible to this node's children — nested function bodies see
* none of them, since labels do not cross a function boundary.
*/
private Label labelNodeChecks(Node node, Label labels) {
switch (node.type) {
case LABELLED_STMT -> {
String name = node.getFirst().getText();
if (Label.contains(labels, name, false)) {
throw new ParserException("label already in scope: " + name);
}
return new Label(name, labelsIterationStatement(node), labels);
}
// §15.7.1 makes a static initialization block a boundary of the same kind
// as a function body: nothing inside it may name a label outside it.
case FN_EXPR, FN_ARROW_EXPR, CLASS_STATIC_BLOCK -> {
return null;
}
case BREAK_STMT -> {
String target = labelReference(node);
if (target != null && !Label.contains(labels, target, false)) {
throw new ParserException("break references an undefined label: " + target);
}
}
case CONTINUE_STMT -> {
String target = labelReference(node);
if (target != null) {
if (!Label.contains(labels, target, false)) {View on GitHub (pinned to a22eb90246)