karatelabs/karate · error · ParserException

continue references an undefined label

Error message

continue references an undefined label: ${target}

What it means

`continue someLabel;` must reference a label that exists in the current scope. As with break, the parser validates CONTINUE_STMT label references against the Label chain and throws when the target is absent (including targets hidden behind a function/arrow/static-block boundary).

Solutions

  1. Correct the label name to an in-scope labeled iteration statement
  2. Replace `continue label;` with plain `continue;` if the innermost loop is the target
  3. Move the continue back into the same function as the labeled loop, or return a flag from the helper and continue at the call site

Example fix

// before
arr.forEach(x => { continue loop; }); // label not visible
// after
for (const x of arr) { if (bad(x)) continue loop; }
Defensive patterns

Strategy: validation

Validate before calling

// Check every `continue X` has a visible label X:
const targets = [...src.matchAll(/continue\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('continue references an undefined label')) { /* fix or drop the label target */ } throw e; }

Prevention

When it happens

Trigger: `continue loopLabel;` where loopLabel is undeclared, misspelled, or declared outside the current function body; the check `!Label.contains(labels, target, false)` fails before the loop-kind check runs.

Common situations: Refactoring loops into helper functions while keeping labeled continues; typos in label names; removing the labeled loop that a nested continue targeted.

Related errors


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

Appendix: source

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

                }
                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;
    }

    /** The label named by a {@code break} / {@code continue}, or null when it has none —
     *  children are [keyword] or [keyword, label]. */
    private static String labelReference(Node node) {
        return node.size() > 1 ? node.get(1).getText() : null;
    }

View on GitHub (pinned to a22eb90246)