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
- Catch MemoryLimitError and report it; also expect the caller's isolate to be dead (see error 310) and acquire a fresh one.
- Refactor the expression to avoid materializing large structures — process in a Code node or stream.
- Raise config.memoryLimit if the data legitimately exceeds 128MB (balance against host memory).
- 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
- Do not materialize large arrays/strings inside expressions — process them in a Code node.
- Set config.memoryLimit deliberately (default 128MB) based on host memory and workload.
- After a MemoryLimitError, release the caller's bridge (it is dead) — see error 310.
- Monitor the 'memory_limit' observability bucket for repeat offenders.
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
- Expression timed out after ${this.config.timeout}ms
- Expression evaluation failed: ${errorMessage}
- Isolate for this caller is no longer available
- Process was forcefully killed (SIGKILL)
- Run ${this.runId} is not suspended. Cannot resume.
AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12).
Data as JSON: /api/errors/4cd24df22e8db75a.
Report an issue: GitHub.