n8n-io/n8n · error · Error

Expression evaluation failed: ${errorMessage}

Error message

Expression evaluation failed: ${errorMessage}

What it means

Thrown as a generic Error('Expression evaluation failed: <errorMessage>') by IsolatedVmBridge.execute() when the isolate raised an error that is NOT an ExpressionError/ExpressionExtensionError, NOT a timeout, and NOT a memory-limit hit. It is the catch-all wrapper for everything else: unexpected runtime exceptions, uncaught TypeErrors from host callbacks (intentionally not special-cased), syntax issues that slipped past tournament, or isolate-internal failures. The original message is appended for diagnostics.

Source

Thrown at packages/@n8n/expression-runtime/src/bridge/isolated-vm-bridge.ts:798

			// so TypeErrors from host callbacks should also go through the generic
			// wrapping for consistent behavior.
			if (
				error instanceof Error &&
				(error.name === 'ExpressionError' || error.name === 'ExpressionExtensionError')
			) {
				throw error;
			}
			const errorMessage = error instanceof Error ? error.message : String(error);
			if (errorMessage.includes('Script execution timed out')) {
				throw new TimeoutError(`Expression timed out after ${this.config.timeout}ms`, {});
			}
			if (errorMessage.includes('memory limit')) {
				throw new MemoryLimitError(
					`Expression exceeded memory limit of ${this.config.memoryLimit}MB`,
					{},
				);
			}
			throw new Error(`Expression evaluation failed: ${errorMessage}`);
		} finally {
			getValueAtPath.release();
			getArrayElement.release();
			callHost.release();
		}
	}

	/**
	 * Reconstruct an error from serialized isolate data.
	 *
	 * Maps error names back to their host-side classes and restores
	 * custom properties that would otherwise be lost crossing the boundary.
	 */
	private reconstructError(data: ErrorSentinel): Error {
		const error = new Error(data.message);
		error.name = data.name || 'Error';
		if (data.stack) {
			error.stack = data.stack;

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Read the appended errorMessage — it is the isolate's original error text and usually pinpoints the cause.
  2. Reproduce the expression in isolation to see the underlying error class.
  3. If a host callback is the source, ensure it throws ExpressionError/ExpressionExtensionError so it is re-thrown verbatim instead of wrapped.
  4. Simplify the expression to the smallest reproducer to isolate the failing operation.
  5. Check for undefined/null access on $json fields that the expression assumes exist.

Example fix

// before — expression assumes a field exists; underlying ReferenceError gets wrapped
const result = evaluator.evaluate('{{ $json.contact.email.toUpperCase() }}', data, caller);
// after — guard access; if it still fails, inspect the wrapped message
try {
  const result = evaluator.evaluate('{{ $json.contact?.email?.toUpperCase() }}', data, caller);
} catch (e) {
  // e.message === 'Expression evaluation failed: Cannot read properties of undefined ...'
  console.error(e.message);
}
Defensive patterns

Strategy: try-catch

Validate before calling

// No general pre-check covers all causes; narrow with targeted guards, e.g. null-safe access
function toNullSafe(expr) { return expr.replace(/\.(\w+)/g, '?.$1'); } // conservative optional-chaining hint

Type guard

function isExpressionEvaluationFailure(e) {
  return e instanceof Error && e.message.startsWith('Expression evaluation failed:');
}

Try / catch

try {
  const result = evaluator.evaluate(expr, data, caller);
} catch (e) {
  if (e instanceof Error && e.message.startsWith('Expression evaluation failed:')) {
    // the appended text after the colon is the isolate's original error message
    console.error('Underlying isolate error:', e.message.slice('Expression evaluation failed:'.length).trim());
  } else throw e;
}

Prevention

When it happens

Trigger: Any isolate execution failure that doesn't match the timeout/memory/ExpressionError branches: a host callback throwing a non-Expression error, a ReferenceError inside the expression, a tournament-transformed code bug, or an isolate-internal fault. The wrapped errorMessage is the isolate's original text.

Common situations: A user expression referencing an undefined variable/method. A host callback (getValueAtPath/getArrayElement/callHost) throwing a non-Expression error due to unexpected data shape. A version skew between tournament transforms and the bridge. Debugging an expression that fails in an unclassified way.

Related errors


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