RocketChat / RocketChat/Rocket.Chat
`crypto.randomUUID()` in `RoomHistoryManager` breaks message history on non-secure origins (plain HTTP, non-localhost) since 8.1
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 46.1k
- Forks
- 13.9k
- Avg merge
- 3d 3h
- Merged PRs (30d)
- 130
Description
Description:
Since 8.1, message history fails to load in every channel when the workspace is served over a plain HTTP origin that is not localhost (e.g. http://<LAN-IP>:3000). The room opens, the message list stays permanently empty, and the browser console throws TypeError: crypto.randomUUID is not a function originating from RoomHistoryManager.getMore().
crypto.randomUUID() is a secure-context-only API. It is available over HTTPS and on http://localhost, but is undefined on arbitrary HTTP origins. Because RoomHistoryManager calls it on the history-loading path, the promise rejects before any message is fetched, so nothing renders at all — including plain-text messages that involve no attachments, files or encryption.
The server is unaffected: GET /api/v1/channels.history returns success: true with the full message set for the same user and room while the UI shows an empty channel. The failure is entirely client-side.
This appears to have been introduced by #37143 ("refactor: remove uuid package"), which replaced uuidv4() with crypto.randomUUID() in apps/meteor/app/ui-utils/client/lib/RoomHistoryManager.ts among other files. That PR merged after the 8.0 branch was cut, matching the observed version boundary: 8.0.x is unaffected, 8.1 and later are affected. The PR review discussed the Node-vs-browser difference of the crypto global, but the secure-context requirement of randomUUID() specifically does not appear to have been considered.
Steps to reproduce:
- Deploy Rocket.Chat 8.6.1 via Docker Compose, reachable at a LAN IP with no TLS, e.g.
http://<LAN-IP>:3001 - Open that URL in a Chromium-based browser and log in
- Open any channel that already contains messages
- Open DevTools → Console
Expected behavior:
Message history loads, as it does on 8.0.x over the same plain-HTTP origin.
Actual behavior:
The channel renders its header and composer but zero messages. The console throws crypto.randomUUID is not a function from RoomHistoryManager.getMore(). Every channel is affected regardless of message content.
Reaching the exact same server instance through a secure context — an SSH tunnel so the browser origin becomes http://localhost:3001 — makes all history render correctly, with no change to code, configuration or data. This isolates the origin's secure-context status as the only variable.
Server Setup Information:
- Version of Rocket.Chat Server: 8.6.1 (our June 2026 production incident was on 8.5.1)
- License Type: Starter
- Number of Users: 14
- Operating System: Ubuntu 24.04.4 LTS (kernel 7.0.0-28-generic)
- Deployment Method: Docker Compose
- Number of Running Instances: 1
- DB Replicaset Oplog: enabled
- NodeJS Version: 22.22.3
- MongoDB Version: 8.2.9, WiredTiger (featureCompatibilityVersion 8.2)
Client Setup Information
- Desktop App or Browser Version: Brave 1.93.129 (Chromium 151.0.7922.71). The official desktop app is Electron/Chromium and is subject to the same secure-context rules.
- Operating System: Windows 11
Additional context
Verification matrix. Same host, same MongoDB instance, same restored dataset (6,809 messages), same browser. Only the image tag and the browser origin changed:
| Server version | http://localhost:3001 (secure context) |
http://<LAN-IP>:3001 (non-secure context) |
|---|---|---|
| 8.6.1 | history renders correctly | empty; crypto.randomUUID is not a function |
| 8.5.1 | history renders correctly | not cleanly verified — see note |
| 8.0.1 (our production) | n/a | history renders correctly |
Note on 8.5.1 over the LAN IP: in our disposable test clone the setup wizard intercepted the session before login, so we could not observe the history-loading path in a non-secure context on that version. We report 8.5.1 as containing the same code path based on #37143, not as independently measured.
Browser environment on the affected origin:
window.isSecureContext // false
typeof crypto.randomUUID // "undefined"
typeof crypto.getRandomValues // "function"
The same page served through http://localhost reports isSecureContext === true and typeof crypto.randomUUID === "function", and history loads.
Impact for self-hosted deployments without TLS. This compounds with the version-durability policy: 8.0 reached EOL in July 2026, so desktop and mobile clients are now cut off from 8.0.x workspaces. Administrators on internal networks without TLS currently have no version available that both accepts desktop clients and renders message history. Chromium's OverrideSecurityRestrictionsOnInsecureOrigin policy restores history in managed browsers, but does not help the desktop app.
Suggested fix. Fall back when the API is unavailable — crypto.getRandomValues() is available in non-secure contexts:
const randomId = (): string =>
globalThis.crypto?.randomUUID?.() ??
'10000000-1000-4000-8000-100000000000'.replace(/[018]/g, (c) =>
(
Number(c) ^
(globalThis.crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (Number(c) / 4)))
).toString(16),
);
Alternatively, reinstate uuid for the client bundle only, which is how several other projects resolved the identical regression: prisma/prisma#29534, payloadcms/payload#11825, TanStack/db#1541, huggingface/chat-ui#868. It would also be worth auditing the rest of #37143 for other client-side call sites.
Prior misattribution, for the record. Our June 2026 incident ran 8.5.1 over http://<LAN-IP>:3000 and presented as "message history stopped rendering for users while the REST API returned the messages normally", resolved only by rolling back to 8.0.1. At the time we attributed it to #41000 / #41079 (the loadMissedMessages → chat.syncMessages migration) and waited on the 8.7.0 milestone. Controlled testing showed that attribution was wrong. Other administrators searching those issues for the same symptom may be misled the same way.
Relevant logs:
Browser console, affected origin (http://<LAN-IP>:3001), Rocket.Chat 8.6.1:
Uncaught (in promise) TypeError: crypto.randomUUID is not a function
at eval (RoomHistoryManager.ts:1:1623)
at new Promise (<anonymous>)
at s.queue (RoomHistoryManager.ts:1:1594)
at s.getMore (RoomHistoryManager.ts:1:2116)
at eval (useGetMore.ts:1:867)
at eval (RoomProvider.tsx:1887)
Repeats once per attempted history load. Also present on the same origin, believed to share the root cause:
Uncaught (in promise) Error: E2E encryption can only be enabled in secure contexts (HTTPS)
at s.startClient (rocketchat.e2e.ts:1:6247)
at eval (useE2EEncryption.ts:1:896)
Browser console, same server via http://localhost:3001: no randomUUID errors, history renders.
Server log: no errors or warnings correlated with the failure. Boot completes normally and Migrations: Already at target migration version 335 — the same migration version the 8.0.1 database was already on. REST API responds success: true for channels.history on the affected room throughout.
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
Start in apps/meteor/app/ui-utils/client/lib/RoomHistoryManager.ts, especially getMore(), and reproduce the failure on a non-secure HTTP origin where crypto.randomUUID is unavailable. Verify the existing history-loading path and its callers, then confirm that message history still loads over both secure and non-secure origins when the API is unavailable.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- frontend
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 78/100