RocketChat / RocketChat/Rocket.Chat
Node external memory grows continuously on GridFS until OOM (heap stable) — RC 8.4.1 / Mongo 8.2.5 on K8s
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 46.1k
- Forks
- 13.9k
- Avg merge
- 3d 3h
- Merged PRs (30d)
- 130
Description
Hi,
I have issue that memory continuously grows until OOM on my RC
(heap stable, nodejs_external_memory_bytes never decreases) — 8.4.1
Description
I have a self-hosted Rocket.Chat instance where memory always grows over time until the pod is OOMKilled / restarts. This repeats in a cycle.
Below is the Rocket.Chat container memory usage over ~30 days. It shows a clear sawtooth: climb toward ~6 GiB → drop (restart/OOM) → climb again every ~7–10 days.
Debugging with metrics
To debug this, I enabled Rocket.Chat Prometheus metrics and monitored:
nodejs_heap_size_total_bytesnodejs_heap_size_used_bytesnodejs_external_memory_bytes
Result:
- Heap used / heap total stay flat and healthy (~0.6–0.75 GiB)
nodejs_external_memory_bytesgrows continuously in a stair-step pattern and never comes down- Container RSS follows the external memory line until OOM
So this is not a classic V8 JS heap leak. The growth is in Node external memory (Buffers / memory outside the V8 heap). am i wrong?
Debugging notes / current hypothesis
While debugging (including with LLM assistance), the evidence points to GridFS / file-related Buffer handling as the likely area:
- Storage type is GridFS
- Workspace has substantial file history and large binaries
- Heap stays flat while external grows and is not released after transfers
- A large external jump on one day did not match heavy uploads that same day (details below), which suggests download/preview/retention of Buffers — not only “big upload then free”
I expected that after upload/download finishes, allocated Buffer/external memory would be released (or at least stabilize). Instead it only grows until restart.
Server Setup Information
- Version of Rocket.Chat Server:
8.4.1(rocketchat/rocket.chat:8.4.1) - Deployment Method: Kubernetes (Helm), 1 replica
- MongoDB Version:
8.2.5(replica set) - Number of Running Instances: 1
- DB Replicaset Oplog / change streams: yes (replica set
rs0) - File storage: GridFS
- Pod memory limit (affected instance):
5734Mi
Upload corpus (Mongo rocketchat_uploads)
- Files: 42,140
- Total size: ~19.43 GiB
- Average size: ~0.47 MiB
- Max size: ~176.24 MiB
Important finding: Aug 5 external jump ≠ heavy uploads that day
On 2026-08-05, Grafana showed external memory jumping roughly ~1.9 GiB → 3.3 GiB (+1.4 GiB) and staying high.
But Mongo uploads that UTC day were small overall:
- Approx total uploaded that day: ~195 MiB
- Peak hour (UTC 15): ~70.8 MiB total, max file ~64.8 MiB
- Morning hours: mostly small clipboard/screenshot PNGs + thumbnails
So the large external step is not explained by that day’s upload volume. This supports looking at download/preview / retained Buffers on GridFS paths, not only upload.
Hourly upload summary for 2026-08-05 (UTC):
| hourUTC | count | totalMB | maxMB |
|---|---|---|---|
| 4 | 4 | 0.1 | ~0 |
| 5 | 18 | 2.6 | 0.9 |
| 6 | 32 | 4.8 | 0.9 |
| 7 | 39 | 5.4 | 1.0 |
| 8 | 49 | 35.5 | 26.6 |
| 9 | 71 | 12.0 | 1.1 |
| 10 | 44 | 4.2 | 0.5 |
| 11 | 60 | 11.5 | 2.1 |
| 12 | 48 | 16.2 | 12.7 |
| 13 | 20 | 10.9 | 8.6 |
| 14 | 25 | 15.4 | 3.5 |
| 15 | 17 | 70.8 | 64.8 |
| 16–22 | low | <2 | small |
Expected behavior
Memory usage should stabilize. After file upload/download/preview completes, external/Buffer memory should be released (or reclaimable), not permanently accumulate until OOM.
Actual behavior
- Container memory grows continuously over days (see 30-day chart)
nodejs_external_memory_bytesstair-steps upward and never decreases- Heap remains stable
- Process recovers only after OOM/restart, then the cycle repeats
- Not proper stdout logs
Already checked
- Not a heap OOM (
nodejs_heap_size_*flat) - Increasing
--max-old-space-sizedoes not address external memory - No documented setting/env found to cap/release Node external/Buffer memory for GridFS
- Upload buffering improvements from 8.1 are already in 8.4.1; 8.5.x notes did not show a clear fix for this continuous external growth pattern
Questions
- Is unbounded growth of
nodejs_external_memory_byteswith flat heap a known issue on GridFS (especially download/serve/preview paths)? - What is the recommended way to confirm Buffer retention on download/preview?
- Aside from migrating off GridFS, is there any supported mitigation?
I would appreciate it if you could help me figure this out, and please correct me if there is any misunderstanding.
Thanks.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
The report names no source files, tests, or entry points; begin by tracing Rocket.Chat’s GridFS upload, download, and preview handling while reproducing the flat-heap, rising-external-memory pattern from the supplied metrics. Done means identifying a confirmed retention path and documenting a reproducible fix or supported mitigation.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- kubernetes, mongodb, node.js, typescript
- Domain
- backend, databases, infrastructure
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Needs clarification
- Newbie friendliness
- 35/100