n8n-io/n8n · error · UnknownIdentifierError

Unknown identifier: '${name}' is not defined

Error message

Unknown identifier: '${name}' is not defined

What it means

When resolving a bare identifier reference (not in a call), the interpreter at interpreter.ts:418-445 checks in order: locally declared variables (including auto-renamed ones), dangerous globals (rejected by `validateIdentifier`), SDK functions, and safe built-ins (`undefined`, `null`, `true`, `false`, `NaN`, `Infinity`). If the name matches none of these, it throws `UnknownIdentifierError`.

Source

Thrown at packages/@n8n/workflow-sdk/src/ast-interpreter/interpreter.ts:445

		}

		// Check for dangerous globals (only when not shadowed by a local)
		validateIdentifier(name, this.getVariableNames(), node, this.sourceCode);

		// Check if it's an SDK function
		if (this.sdkFunctions.has(name)) {
			return this.sdkFunctions.get(name);
		}

		// Allow certain safe built-ins
		if (name === 'undefined') return undefined;
		if (name === 'null') return null;
		if (name === 'true') return true;
		if (name === 'false') return false;
		if (name === 'NaN') return NaN;
		if (name === 'Infinity') return Infinity;

		throw new UnknownIdentifierError(name, node.loc ?? undefined, this.sourceCode);
	}

	/**
	 * Visit a template literal.
	 * Handles n8n runtime variables by preserving them as escaped strings.
	 */
	private visitTemplateLiteral(node: ESTree.TemplateLiteral): string {
		let result = '';

		for (let i = 0; i < node.quasis.length; i++) {
			const quasi = node.quasis[i];
			// Use cooked value (with escape sequences processed), or raw if cooked is null
			result += quasi.value.cooked ?? quasi.value.raw;

			// If there's an expression after this quasi
			if (i < node.expressions.length) {
				const expr = node.expressions[i];
				const value = this.evaluateTemplateExpression(expr);

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Declare the variable with `const` before referencing it
  2. Check spelling against declared variable names
  3. For globals: use SDK alternatives (e.g., `$now`/`$today` for dates, n8n expressions for Math)

Example fix

// before
const result = myVarible; // typo

// after
const result = myVariable;
Defensive patterns

Strategy: validation

Validate before calling

import { ALLOWED_SDK_FUNCTIONS } from '@n8n/workflow-sdk/ast-interpreter/validators';

const SAFE_BUILTINS = new Set(['undefined', 'null', 'true', 'false', 'NaN', 'Infinity']);

function findUndefinedReferences(code: string, declaredVars: Set<string>): string[] {
  const ast = parse(code, { ecmaVersion: 'latest', sourceType: 'module' });
  const undefined: string[] = [];
  walk(ast, (node) => {
    if (
      node.type === 'Identifier' &&
      !declaredVars.has(node.name) &&
      !ALLOWED_SDK_FUNCTIONS.has(node.name) &&
      !SAFE_BUILTINS.has(node.name)
    ) {
      // Exclude property names and callee names (they are contextual)
      undefined.push(node.name);
    }
  });
  return [...new Set(undefined)];
}

Try / catch

import { UnknownIdentifierError } from '@n8n/workflow-sdk/ast-interpreter/errors';

try {
  interpretSDKCode(sdkCode, sdkFunctions);
} catch (e) {
  if (e instanceof UnknownIdentifierError) {
    // show the identifier name and suggest declaring it or checking spelling
  }
  throw e;
}

Prevention

When it happens

Trigger: Referencing an undeclared variable: `x` where `x` was never declared with `const`. Note that blocked globals like `console`, `Math`, `Date`, `process`, `fetch` are caught earlier by `validateIdentifier` (throwing `SecurityError`), so this throw is specifically for names that are simply unknown — not dangerous, just undefined.

Common situations: Typo in a variable name; referencing a variable from an outer scope that isn't in SDK scope; using an identifier that was declared in a different code path.

Related errors


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