microsoft / microsoft/onnxruntime

[Bug] [Node.js] First InferenceSession creation allocates 15-43GB on macOS ARM64 — no session cycling

Open
#27,767 2 comments 0 reactions 1 assignee View on GitHub

@fs-eire is already working on this.

Since Mar 19, 2026.

api:Javascript model:transformer platform:web
Dominant language
C++
Stars
21.9k
Forks
4.2k
Avg merge
4d 11h
Merged PRs (30d)
184

Description

### Describe the bug

Creating a **single** `InferenceSession` for a ~500MB fp32 ONNX embedding model (`nomic-ai/nomic-embed-text-v1.5`) causes the Node.js process to allocate 15-43GB of RSS memory on macOS ARM64. This is not a session create/release cycle leak (as described in #25325) — this happens on the **first and only** session creation, before any inference runs.

The allocation spike is instantaneous — RSS goes from ~2.4GB to 15GB in under 2 seconds (observed via polling `ps -o rss`). On `onnxruntime-node@1.22.0`, it reached 43GB and Jetsam-killed the process on a 36GB machine.

### Urgency

This is a showstopper for any Node.js application that loads ONNX models on macOS ARM64. We tested three versions — all broken with different symptoms. We've had to remove ONNX from our default pipeline entirely.

### To reproduce

```javascript
// Minimal reproduction — single session, no cycling
import { pipeline } from "@huggingface/transformers";

// This single call triggers the 15GB+ allocation
const embedder = await pipeline("feature-extraction", "nomic-ai/nomic-embed-text-v1.5", {
dtype: "fp32",
device: "cpu"
});

// Process RSS is already 15GB+ before this line executes
const result = await embedder("hello world", { pooling: "mean", normalize: true });
```

Running in a Node.js Worker Thread (via `worker_threads`) makes it worse but the bug reproduces on the main thread too.

### Environment

- **OS:** macOS 15.7.3 (Sequoia) — `Darwin Kernel Version 24.6.0`
- **Hardware:** MacBook Pro M3 Pro, 36GB RAM
- **Node.js:** 22.22.0
- **Architecture:** ARM64 (Apple Silicon)

### Versions tested

| onnxruntime-node | @huggingface/transformers | Result |
|-----------------|--------------------------|--------|
| **1.21.0** | 3.8.1 | `FATAL ERROR: HandleScope::HandleScope Entering the V8 API without proper locking in place` — process crashes immediately in Worker Thread |
| **1.22.0** | 3.8.1 | 43GB RSS allocation on first session create. Jetsam kills the process. On a second attempt, hard-froze the MacBook requiring force reboot (no panic log, no Jetsam report — pure deadlock). |
| **1.24.3** | 3.8.1 | 15GB RSS allocation on first session create. Jetsam kills the process within seconds. |

All versions installed via npm `overrides` to force the transitive dependency from `@huggingface/transformers`:
```json
{ "overrides": { "onnxruntime-node": "1.24.3" } }
```

### Memory watchdog data (v1.24.3)

We ran our indexing tool with a 2-second RSS polling watchdog:

```
[2] RSS: 2375 MB ← model file loaded into memory, session not yet created
[3] RSS: 2376 MB
[4] RSS: 2433 MB
[5] RSS: 15064 MB ← session creation completed — 12.6GB spike in <2 seconds
KILLING — exceeded 4GB watchdog threshold
```

### Jetsam report data (v1.22.0 — earlier test without watchdog)

From `/Library/Logs/DiagnosticReports/JetsamEvent-2026-03-19-091753.ips`:

```
"largestProcess": "node"
"free": 4507 pages (73MB)

Top processes at kill time:
node: 43314 MB (2,772,107 pages × 16KB)
com.apple.Virtualization.Virtual: 8105 MB
WindowServer: 1314 MB
```

The `node` process consumed **43.3GB** on a **36GB machine** — clearly allocating virtual memory far beyond physical RAM.

### Relationship to #25325

Issue #25325 describes memory leaks during **session create/release cycling**. Our bug is different:

- **Single session creation** — no release, no cycling
- **Instantaneous allocation** — not a gradual leak
- **First load** — happens before any inference call
- **Scale is wrong** — a 500MB model should not allocate 15-43GB

This may share root cause with #25325 (allocator retention, arena pre-allocation) but the trigger is different. The community workaround for #25325 (spawn short-lived child processes) doesn't help here because the leak happens on the first and only session.

### What we've tried

- `CpuMemArena: false` — not directly configurable through `@huggingface/transformers` pipeline API
- Different `dtype` values — fp32 tested, q8 was not tested before we abandoned ONNX
- Worker Thread vs Main Thread — both leak, Worker Thread is worse
- Three different `onnxruntime-node` versions — all broken

### Expected behavior

Loading a 500MB ONNX model should use approximately 500MB-1GB of RSS, not 15-43GB.

### Impact

We maintain a local code search MCP server for AI coding assistants. We had to:
1. Remove ONNX from the default pipeline
2. Make our GitHub repository private (the published code crashes machines)
3. Abandon 10 sprints of work built on `@huggingface/transformers` ONNX backend
4. Plan a full replacement with `node-llama-cpp` (GGUF models) as the default embedding backend

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.