n8n-io/n8n · error · MemoryLimitError

Expression exceeded memory limit of ${this.config.memoryLimi

Error message

Expression exceeded memory limit of ${this.config.memoryLimit}MB

What it means

Thrown as MemoryLimitError by IsolatedVmBridge.execute() when the isolate aborts with a message containing 'memory limit'. The isolate has a fixed memory ceiling (config.memoryLimit, default 128MB via DEFAULT_BRIDGE_CONFIG); allocations beyond it abort the script. MemoryLimitError extends ExpressionError and maps to the 'memory_limit' observability bucket. Critically, an OOM disposes the underlying isolate — subsequent expressions on the same caller will fail with error 310.

Source

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

			return result;
		} catch (error) {
			// Re-throw reconstructed errors as-is.
			// Note: TypeError is intentionally NOT included here — the isolate's
			// E() handler swallows TypeErrors (failed attack attempts return undefined),
			// 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.
	 */

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Catch MemoryLimitError and report it; also expect the caller's isolate to be dead (see error 310) and acquire a fresh one.
  2. Refactor the expression to avoid materializing large structures — process in a Code node or stream.
  3. Raise config.memoryLimit if the data legitimately exceeds 128MB (balance against host memory).
  4. Audit observability 'memory_limit' events to find which expression/node is the offender.

Example fix

// before — materialize a huge array in an expression
const result = evaluator.evaluate('{{ $json.bigRows.map(r => ({...r, x: heavy(r)})) }}', data, caller);
// after — defer to a node, and handle the dead isolate
try {
  const result = evaluator.evaluate('{{ $json.bigRows.length }}', data, caller);
} catch (e) {
  if (e instanceof MemoryLimitError) {
    await evaluator.release(caller); // isolate is dead; drop it
    // route the heavy work to a Code/Function node instead
  }
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Bound input size before evaluating to reduce OOM risk
function isSafeToEvaluate(data, maxItems = 100000) {
  const rows = data?.$json?.rows ?? data?.$json;
  return !Array.isArray(rows) || rows.length <= maxItems;
}

Type guard

import { MemoryLimitError } from '@n8n/expression-runtime';
function isMemoryLimitError(e) { return e instanceof MemoryLimitError || e?.name === 'MemoryLimitError'; }

Try / catch

import { MemoryLimitError } from '@n8n/expression-runtime';
try {
  const result = evaluator.evaluate(expr, data, caller);
} catch (e) {
  if (e instanceof MemoryLimitError) {
    // isolate is now dead for this caller; release it and fail/recover the execution
    await evaluator.release(caller);
  } else throw e;
}

Prevention

When it happens

Trigger: An expression allocates beyond the isolate heap: building a giant array (e.g. let a=[]; while(true){a.push(new Array(1000000).fill(1))}, the test fixture), unbounded string concatenation, or materializing a very large $json. Reproduced in tests with memoryLimit:8.

Common situations: A user expression that accidentally expands a large dataset (e.g. mapping a huge array into a bigger structure). memoryLimit configured too low for legitimate data shapes. A bug causing unbounded growth in a loop. Processing an attachment/log file inline in an expression.

Related errors


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