karatelabs/karate · error · ParserException
a function declaration may not be the body of
Error message
a function declaration may not be the body of ${where} What it means
In ECMAScript, the body clause of `if`/`else`, loops, and labelled statements is a single Statement, while a function declaration is a StatementListItem, not a Statement. Karate's JS parser enforces this strictly and rejects `if (x) function f() {}` style code instead of tolerating non-standard Annex B slop. A braced block body is the legal form.
Solutions
- Wrap the function declaration in braces: `if (cond) { function f() {} }`.
- Better, declare the function before/outside the clause and just call it in the clause.
- Convert to a function expression assigned to a variable: `if (cond) { const f = () => {}; }`.
- Run the same code in Node --strict to catch these before putting them in Karate scripts.
Example fix
// before
if (ready) function init() { start(); }
// after
if (ready) { function init() { start(); } init(); } Defensive patterns
Strategy: validation
Validate before calling
// reject unbraced clauses whose body starts with 'function'
function hasUnbracedFnBody(src) {
return /(^|[^\w$])(if|else|for|while|do|\w+:)\s*function\s*[\w$]*\s*\(/.test(src);
}
if (hasUnbracedFnBody(src)) throw new Error('brace the function declaration body'); Try / catch
try {
return karate.eval(script);
} catch (e) {
if (String(e.message).includes('may not be the body of')) {
throw new Error('Add braces around the clause body in: ' + script);
}
throw e;
} Prevention
- Always brace if/else/loop bodies — never rely on single-statement clauses.
- Declare functions at statement-list positions, not as clause bodies.
- Enable a linter (ESLint consistent-return / no inner declarations style rules) on embedded JS.
- When transpiling code into Karate scripts, keep the braces the transpiler emits.
When it happens
Trigger: Writing an unbraced clause whose body is a function declaration, e.g. `if (cond) function f() {}`, `while (x) function f() {}`, or `label: function f() {}`, in any Karate JS expression/script parsed by JsParser.
Common situations: Code written by habit from sloppy browser environments that tolerate `if (x) function f(){}`; minified or transpiled code pasted in; authors omitting braces to save a line.
Related errors
- a class declaration may not be the body of
- a lexical declaration may not be the body of
- 'await' is a reserved word in a class static initialization…
- 'break' may not cross a class static initialization block
- 'continue' may not cross a class static initialization block
AI-assisted analysis of karatelabs/karate@a22eb90246 (2026-09-12).
Data as JSON: /api/errors/a8cbf561528f9d51.
Report an issue: GitHub.
Appendix: source
Thrown at karate-js/src/main/java/io/karatelabs/parser/JsParser.java:758
}
return false;
}
/** Throws if any direct {@code STATEMENT} child of {@code node} is itself a
* function declaration (its first non-token child is an {@code FN_EXPR}) — the
* body of `if` / loop / labelled clauses is a Statement, and FunctionDeclaration
* is a StatementListItem only. A braced body (BLOCK) is fine. */
private static void checkNoFunctionDeclarationBody(Node node, String where) {
for (int i = 0, n = node.size(); i < n; i++) {
Node child = node.get(i);
if (child.isToken() || child.type != NodeType.STATEMENT) {
continue;
}
for (int j = 0, m = child.size(); j < m; j++) {
Node inner = child.get(j);
if (!inner.isToken()) {
if (inner.type == NodeType.FN_EXPR) {
throw new ParserException(
"a function declaration may not be the body of " + where);
}
break; // first non-token child decides
}
}
}
}
/** Throws if any direct {@code STATEMENT} child of {@code node} is itself a
* LexicalDeclaration ({@code let}/{@code const}) or a ClassDeclaration — the body
* of an `if`/`else`/loop clause is a Statement, and both are Declarations, not
* Statements (§13.6/§14.x). A {@code var} declaration hoists and stays legal; a
* braced body (BLOCK) is fine. Mode-independent — there is no Annex B carve-out
* for these the way there is for FunctionDeclaration in an `if` clause. */
private static void checkNoLexicalOrClassDeclarationBody(Node node, String where) {
for (int i = 0, n = node.size(); i < n; i++) {
Node child = node.get(i);
if (child.isToken() || child.type != NodeType.STATEMENT) {View on GitHub (pinned to a22eb90246)