karatelabs/karate · error · ParserException
duplicate binding name
Error message
duplicate binding name '${name}' is not allowed in a catch parameter What it means
A `catch (pattern)` binding may not contain duplicate names. Karate collects every bound name in the catch parameter (including destructured bindings like `catch ({e, e})`) and rejects duplicates, per the ECMAScript CatchParameter uniqueness rule.
Solutions
- Remove or rename the duplicated binding in the catch pattern.
- If both sources are needed, alias one: `catch ({message: msg1, message: msg2})` — wait, that is still the same key; instead bind once and derive the second value in the body.
- If the pattern was accidentally duplicated, simplify to a single binding: `catch (e) { const { message } = e; }`.
Example fix
// before
try { risky(); } catch ({ message, message }) { log(message); }
// after
try { risky(); } catch (err) { log(err.message); } Defensive patterns
Strategy: validation
Validate before calling
function assertUniqueCatchBinding(catchSrc) {
const inner = catchSrc.slice(catchSrc.indexOf('(') + 1, catchSrc.lastIndexOf(')'));
const names = inner.match(/[\w$]+/g) || [];
const seen = new Set();
for (const n of names) {
if (seen.has(n)) throw new Error('duplicate catch binding: ' + n);
seen.add(n);
}
} Try / catch
try {
karate.eval(script);
} catch (e) {
if (String(e.message).includes("not allowed in a catch parameter")) {
// simplify the catch pattern to a single binding
} else throw e;
} Prevention
- Prefer a single simple catch binding (`catch (err)`) and destructure in the body.
- Avoid hand-writing destructured catch patterns; the collision risk outweighs the brevity.
- Code generators should deduplicate keys when emitting object patterns.
When it happens
Trigger: Writing `try {} catch (e, ...)` is impossible in JS, but `catch (e) ` duplication arises via destructuring: `catch ({message, message}) {}` or array patterns like `catch ([x, x]) {}` in Karate JS.
Common situations: Copy-paste errors in destructured catch clauses; merging bindings from two sources into one pattern without noticing the collision; code-generation templates producing duplicated keys.
Understand the failure class
Background: "must be a positive integer", "cannot be empty", "invalid argument": how invalid-argument errors work across open-source libraries — this error's family across 33 libraries.
Related errors
- invalid shorthand initializer: only allowed in…
- invalid destructuring: rest element must be the last…
- invalid destructuring: rest element cannot have an…
- invalid
- invalid : parenthesized destructuring pattern
AI-assisted analysis of karatelabs/karate@a22eb90246 (2026-09-12).
Data as JSON: /api/errors/f21fdaf45bb82cbf.
Report an issue: GitHub.
Appendix: source
Thrown at karate-js/src/main/java/io/karatelabs/parser/JsParser.java:1127
}
if (ch.token.type == IDENT) {
binding = ch; // simple catch binding — no duplicate possible
break;
}
// skip the L_PAREN
} else {
binding = ch; // LIT_ARRAY / LIT_OBJECT pattern
break;
}
}
if (binding == null) {
return;
}
List<String> names = new ArrayList<>();
collectBoundNames(binding, names);
String dup = firstDuplicate(names);
if (dup != null) {
throw new ParserException(
"duplicate binding name '" + dup + "' is not allowed in a catch parameter");
}
if (strict) {
for (String name : names) {
if (isEvalOrArguments(name)) {
throw new ParserException(
"'" + name + "' is not a valid binding name in strict mode");
}
}
}
}
/** A strict var/let/const declaration may not bind {@code eval} / {@code arguments}
* — including inside a destructuring pattern. (Lexical duplicate-BoundNames for
* let/const patterns is a distinct rule, deferred — VAR_DECL doesn't carry the
* let-vs-var distinction.) */
private static void checkVarDeclName(Node varDecl) {
List<String> names = new ArrayList<>();View on GitHub (pinned to a22eb90246)