karatelabs/karate · error · ParserException
identifier ' ' has already been declared
Error message
identifier '${name}' has already been declared What it means
This is a strict-mode-style early error from the Karate JS parser: a lexical declaration (let/const/class) re-declares an identifier that was already lexically declared in the same scope. JavaScript forbids duplicate lexical bindings; in sloppy mode duplicate function declarations are tolerated, but in strict mode (Karate's default) any duplicate errors at parse time. It is thrown before any code executes, so nothing of the script runs.
Solutions
- Rename one of the conflicting declarations so each lexical name is unique per scope
- Drop the redundant `let`/`const` keyword and just reassign the existing binding (e.g. `x = 2;`)
- Move one declaration into a nested block `{ ... }` if a separate binding is genuinely intended
- Check for accidental duplicated paste of a declaration line or block
Example fix
// before let temp = a; let temp = b; // duplicate // after let tempA = a; let tempB = b;
Defensive patterns
Strategy: validation
Validate before calling
// before running a Karate JS snippet, check for duplicate let/const/class names per scope
function hasDuplicateLexicalDecls(src) {
const decls = [...src.matchAll(/\b(?:let|const|class)\s+([A-Za-z_$][\w$]*)/g)].map(m => m[1]);
return decls.length !== new Set(decls).size;
} Try / catch
try {
karate.configure('...', jsSnippet);
} catch (e) {
if (String(e).includes('has already been declared')) {
// surface the offending name and fix the script
}
throw e;
} Prevention
- Use a linter (ESLint no-redeclare) on embedded JS before deployment
- Prefer a single declaration keyword style per scope (all let/const)
- Avoid copy-pasting blocks that redeclare names already in scope
When it happens
Trigger: Parsing a script where two let/const/class declarations in the same block use the same name, e.g. `let x = 1; let x = 2;` — the duplicate-name check over lexNames fires when seen.add(name) fails and the name is either a non-function lexical binding or the code is strict.
Common situations: Copy-pasting a variable declaration into a Karate JS block that already declares it; refactoring that leaves both `let` and `const` for the same name in one function or block; converting `var` to `let` in two places without noticing the collision.
Related errors
- duplicate private name
- ' ' is not a valid function name in strict mode
- duplicate parameter name
- invalid assignment to
- octal literals are not allowed in strict mode
AI-assisted analysis of karatelabs/karate@a22eb90246 (2026-09-12).
Data as JSON: /api/errors/08b2675679161194.
Report an issue: GitHub.
Appendix: source
Thrown at karate-js/src/main/java/io/karatelabs/parser/JsParser.java:1268
}
} else if (d.type == NodeType.FN_EXPR && !topLevel) {
String name = declarationName(d);
if (name != null) {
lexNames.add(name); // function-bound — deliberately not in lexNonFn
}
}
}
if (lexNames.isEmpty()) {
return; // no lexical declarations → no duplicate and no clash possible
}
// Duplicate LexicallyDeclaredNames. Annex B.3.3: a sloppy duplicate bound only
// by FunctionDeclarations is allowed; everything else (and all of strict) errors.
Set<String> seen = new HashSet<>();
for (String name : lexNames) {
if (!seen.add(name)) {
boolean onlyFunctions = !lexNonFn.contains(name);
if (strict || !onlyFunctions) {
throw new ParserException(
"identifier '" + name + "' has already been declared");
}
}
}
// Lexical names may not also be var-declared anywhere in the scope (vars hoist
// through nested blocks; at top level a FunctionDeclaration is itself var-scoped).
List<String> varNames = new ArrayList<>();
for (Node stmt : statements) {
collectVarNames(stmt, varNames);
if (topLevel) {
Node d = firstNonToken(stmt);
if (d != null && d.type == NodeType.FN_EXPR) {
String name = declarationName(d);
if (name != null) {
varNames.add(name);
}
}
}View on GitHub (pinned to a22eb90246)