n8n-io/n8n · error · InterpreterError

Cannot call non-function

Error message

Cannot call non-function

What it means

After resolving the callable value (from `sdkFunctions`, `variables`, or an object property), the interpreter checks `typeof func === 'function'` at interpreter.ts:295. If the resolved value isn't callable, it throws `InterpreterError`. This catches cases where you call a variable holding a non-function, or a property that doesn't exist on an object (resolves to `undefined`).

Source

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

						`Allowed methods: ${allowedMethodNames().join(', ')}. ` +
						'Native array/string methods are not available in SDK code; ' +
						'use a Code node or an n8n expression for runtime logic.',
				);
			}

			if (thisArg && typeof thisArg === 'object') {
				func = (thisArg as Record<string, unknown>)[methodName];
			}
		} else {
			throw new UnsupportedNodeError(
				`Callee type ${node.callee.type}`,
				node.callee.loc ?? undefined,
				this.sourceCode,
			);
		}

		if (typeof func !== 'function') {
			throw new InterpreterError(
				'Cannot call non-function',
				node.loc ?? undefined,
				this.sourceCode,
			);
		}

		// Evaluate arguments
		const args = node.arguments.map((arg) => this.evaluate(arg));

		// Call the function
		return func.apply(thisArg, args);
	}

	/**
	 * Visit a member expression (for property access, not method calls).
	 */
	private visitMemberExpression(node: ESTree.MemberExpression): unknown {
		validateMemberExpression(node, this.sourceCode);

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Verify the value is actually a function — check what the variable was assigned
  2. Use only documented SDK method names on builder objects
  3. Check for typos in method names against `allowedMethodNames()`

Example fix

// before
const config = { name: 'X' };
config({ extra: true }); // config is an object, not a function

// after
const wf = workflow({ name: 'X' });
wf.add({ extra: true });
Defensive patterns

Strategy: type-guard

Validate before calling

// Pre-check: verify that every call target resolves to a function
// by tracing variable assignments in the SDK code

Type guard

// In the CALLER (TypeScript), after getting the interpreter result:
function isFunction(value: unknown): value is Function {
  return typeof value === 'function';
}

// In SDK code, guard with typeof before calling (typeof IS supported):
// const fn = typeof x === 'function' ? x : null;
// if (fn) { fn(); } — but note: if/call blocks are not available in SDK code.
// Best: ensure the value is a function by construction.

Try / catch

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

try {
  interpretSDKCode(sdkCode, sdkFunctions);
} catch (e) {
  if (e instanceof InterpreterError && e.message.includes('Cannot call non-function')) {
    // verify method names against allowedMethodNames() and check variable assignments
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling a variable that holds a non-function: `const x = 5; x()`. Or calling a property name that doesn't exist on a builder object: `obj.nonexistent()` resolves `func` to `undefined`, which fails the typeof check.

Common situations: Method name typo on an SDK builder; calling a variable that was assigned a literal value; accessing a property that resolves to undefined and then calling it.

Related errors


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