Node.js ERR_WORKER_OUT_OF_MEMORY in worker_threads
Diagnose ERR_WORKER_OUT_OF_MEMORY when a Node worker thread exceeds its resourceLimits, and tune per-worker heap or reduce the workload.
Symptoms
- Error [ERR_WORKER_OUT_OF_MEMORY]: Worker terminated due to reaching memory limit
- The worker exits abruptly with code 1 while the main thread stays alive
- Large image or parse jobs crash only inside worker threads
Possible causes
- resourceLimits.maxOldGenerationSizeMb set too low for the payload
- A worker accumulates data in a long-lived scope without releasing it
- Large input is cloned into the worker faster than it can be processed
- A recursive algorithm builds an unbounded call and heap footprint
Diagnosis steps
Log the worker exit code and resourceLimits
new Worker(file, { resourceLimits: { maxOldGenerationSizeMb: 64 } })Interpretation
If the limit is small and the job is large, the kill is expected; compare against the job size.
Take a heap snapshot from the worker before it dies
worker.postMessage({ cmd: 'snapshot' })Interpretation
Retained objects that grow between snapshots identify an unbounded accumulation.
Reproduce outside workers to separate logic bugs from the limit
Interpretation
If the same job uses far less memory in the main thread, the issue is the configured limit or streaming behavior.
Root cause
worker_threads let you cap memory with resourceLimits. When the worker heap exceeds the cap, V8 terminates it and surfaces ERR_WORKER_OUT_OF_MEMORY rather than an ordinary heap OOM. A low cap plus a memory-hungry job, or a genuine leak in the worker, produces the same error.
Fix
Right-size resourceLimits.maxOldGenerationSizeMb to the payload and stream large inputs instead of buffering whole files in the worker. Free references to processed chunks, avoid recursive accumulation, and recycle workers for repeated large jobs instead of keeping state.
Verify the fix
Re-run the job with adjusted limits and monitor worker memory; the worker completes without an out-of-memory termination and exits with code 0.
Symptoms
A worker thread dies with ERR_WORKER_OUT_OF_MEMORY and exit code 1 while the parent process keeps running. The failure is deterministic for large payloads and absent for small ones.
Diagnosis
Inspect the configured limits and the actual demand:
const worker = new Worker('./job.js', {
resourceLimits: { maxOldGenerationSizeMb: 128 },
});
worker.on('exit', (code) => console.error('worker exit', code));
Take snapshots inside the worker and compare retained sizes to spot unbounded growth.
Fix
Raise the cap to match the job, or better, stream input and process incrementally:
for await (const chunk of stream) {
process(chunk); // do not retain chunk
}
Recreate workers between large jobs so heap state does not accumulate.
Verification
Run the same payload and confirm the worker finishes and exits cleanly. A quick heap trace should show a bounded peak rather than a climbing baseline.