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

  1. Change every top-level declaration to const.
  2. If reassignment is needed, restructure to a single const with a ternary or an SDK helper that returns the final value.
  3. 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

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


AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12). Data as JSON: /api/errors/9e8316bb496b952e. Report an issue: GitHub.