← Debugging Guides

阅读中文版本

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.

advanceddebuggingnodeworker-threadsmemory

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.