n8n-io/n8n · error · SecurityError
'${node.kind}' declarations are not allowed. Use 'const' onl
Error message
'${node.kind}' declarations are not allowed. Use 'const' only. What it means
Thrown as SecurityError (extends InterpreterError) by visitVariableDeclaration when a variable declaration's kind is not 'const'. The SDK vocabulary only permits const bindings to keep evaluated code referentially transparent and free of reassignment. The offending kind (let/var) is interpolated into the message and a code frame is appended when location is available.
Source
Thrown at packages/@n8n/workflow-sdk/src/ast-interpreter/interpreter.ts:96
result = this.evaluate(stmt.expression);
break;
case 'ExportDefaultDeclaration':
return this.evaluate(stmt.declaration as ESTree.Expression);
default:
throw new UnsupportedNodeError(stmt.type, stmt.loc ?? undefined, this.sourceCode);
}
}
return result;
}
/**
* Process a variable declaration.
*/
private visitVariableDeclaration(node: ESTree.VariableDeclaration): void {
// Only allow const declarations
if (node.kind !== 'const') {
throw new SecurityError(
node.kind,
node.loc ?? undefined,
this.sourceCode,
`'${node.kind}' declarations are not allowed. Use 'const' only.`,
);
}
for (const declarator of node.declarations) {
if (declarator.id.type !== 'Identifier') {
throw new UnsupportedNodeError(
'Destructuring in variable declaration',
declarator.loc ?? undefined,
this.sourceCode,
);
}
const name = declarator.id.name;
View on GitHub (pinned to 5ac6606e81)
Solutions
- Change every top-level declaration to const.
- If reassignment is needed, restructure to a single const with a ternary or an SDK helper that returns the final value.
- Run a lint rule that flags non-const declarations in SDK files.
Example fix
// before let result = compute(x); result = result + 1; export default result; // after const base = compute(x); export default base + 1;
Defensive patterns
Strategy: validation
Validate before calling
import { parseSDKCode } from '@n8n/workflow-sdk';
function preflightConstOnly(code: string): void {
const ast = parseSDKCode(code);
for (const stmt of ast.body) {
if (stmt.type === 'VariableDeclaration' && stmt.kind !== 'const') {
throw new Error(`SDK code must use 'const' (found '${stmt.kind}') near line ${stmt.loc?.start.line}`);
}
}
} Type guard
import type { VariableDeclaration } from 'estree';
function isConstDeclaration(node: VariableDeclaration): boolean {
return node.kind === 'const';
} Try / catch
try {
return interpret(code, sdkFunctions);
} catch (e) {
if (e?.name === 'SecurityError' && /declarations are not allowed/i.test(e?.message ?? '')) {
return { error: 'Use const only in SDK code.', detail: e.message };
}
throw e;
} Prevention
- Use const for all top-level bindings in SDK code.
- Restructture reassignment into a single const with a ternary or SDK helper result.
- Add a lint rule flagging let/var in SDK files.
When it happens
Trigger: Writing `let x = 1;` or `var y = 2;` at the top level of SDK code; auto-formatters or codegen emitting let by default; refactoring const to let during debugging and forgetting to revert.
Common situations: Developers defaulting to let out of habit; copy-pasting snippets that use let/var; linters that rewrite const to let for later reassignment.
Related errors
- Unsupported syntax: '${nodeType}' is not allowed in SDK code
- ${label} "${candidate}" escapes ${root}
- Invalid skill at ${sourceDirectory}: ${errors.join('; ')}
- Webhook URL must use HTTPS. Got: ${url.protocol}
- Webhook URL cannot target localhost
AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12).
Data as JSON: /api/errors/9e8316bb496b952e.
Report an issue: GitHub.