karatelabs/karate · error · ParserException

break references an undefined label

Error message

break references an undefined label: ${target}

What it means

`break someLabel;` must reference a label that is actually in scope at the break site. Karate resolves label references at parse time in labelNodeChecks; if a BREAK_STMT names a target not present in the current Label chain (function bodies and static blocks truncate the chain), this early error is thrown.

Solutions

  1. Fix the label name to match an in-scope labeled statement
  2. Remove the label from the break (`break;`) if only the innermost loop/block should be exited
  3. Restructure so the labeled statement and the break live in the same function body (labels do not cross function boundaries)

Example fix

// before
function f() { outer: for (;;) { g(); } }
function g() { break outer; } // invalid
// after
function f() { outer: for (;;) { break outer; } }
Defensive patterns

Strategy: validation

Validate before calling

// Check every `break X` has a visible label X in the same function:
const targets = [...src.matchAll(/break\s+([A-Za-z_$][\w$]*)/g)].map(m=>m[1]);
const declared = new Set([...src.matchAll(/([A-Za-z_$][\w$]*):/g)].map(m=>m[1]));
const missing = targets.filter(t => !declared.has(t));

Try / catch

try { eval(js); } catch (e) { if (String(e).includes('break references an undefined label')) { /* fix or remove the label target */ } throw e; }

Prevention

When it happens

Trigger: `break outer;` where no label named `outer` exists, or where `outer` is defined outside the enclosing function/arrow/static block (chain is reset to null there). Also plain `break outer` in non-loop labeled blocks where the label was never declared.

Common situations: Typos in label names; moving a `break label` into an extracted function or callback so the label is no longer visible; deleting the labeled loop but keeping the break.

Related errors


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

Appendix: source

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

     */
    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)) {
                        throw new ParserException("continue references an undefined label: " + target);
                    }
                    if (!Label.contains(labels, target, true)) {
                        throw new ParserException("continue label does not name a loop: " + target);
                    }
                }
            }
            default -> {
            }
        }
        return labels;
    }

View on GitHub (pinned to a22eb90246)