{"record":{"id":"e7c15a1a2d45cacc","repo":"clockworklabs/SpacetimeDB","slug":"math-random-is-not-available-in-spacetimedb-module","errorCode":null,"errorMessage":"Math.random is not available in SpacetimeDB modules. Use ctx.random instead.","messagePattern":"Math\\.random is not available in SpacetimeDB modules\\. Use ctx\\.random instead\\.","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"crates/core/src/host/v8/builtins/delete_math_random.js","lineNumber":6,"sourceCode":"delete Math.random;\nObject.defineProperty(Math, 'random', {\n  enumerable: false,\n  configurable: true,\n  get() {\n    throw new TypeError(\n      'Math.random is not available in SpacetimeDB modules. Use ctx.random instead.'\n    );\n  },\n});\n","sourceCodeStart":1,"sourceCodeEnd":11,"githubUrl":"https://github.com/clockworklabs/SpacetimeDB/blob/524b4487d949b61a07d4f39c862d1290259dfd20/crates/core/src/host/v8/builtins/delete_math_random.js#L1-L11","documentation":"SpacetimeDB executes JavaScript modules inside a deterministic V8 sandbox and replaces Math.random with a throwing getter (crates/core/src/host/v8/builtins/delete_math_random.js). Randomness must come from the host so execution can be replayed consistently across replicas, so any call to Math.random() raises a TypeError redirecting you to ctx.random.","triggerScenarios":"Calling Math.random() anywhere in module code running in the SpacetimeDB V8 host (reducer, scheduled function, module-scope initialization); importing an npm dependency that calls or shims Math.random at load time.","commonSituations":"Porting existing Node.js or browser game logic; pulling in uuid v4, seedrandom, or noise libraries that self-seed via Math.random; assuming browser/Node globals exist unchanged inside the module sandbox.","solutions":["Replace Math.random() with ctx.random(), using the ReducerContext passed into your reducer or scheduled function","Thread the context (or a () => number closure bound to ctx.random) into helpers and classes that need randomness instead of calling the global","Vendor/patch third-party dependencies to accept an injectable RNG function rather than calling Math.random internally","If you only need uniqueness (ids, tokens), derive values from row ids or Identity instead of RNG"],"exampleFix":"// before\nfunction rollDice() { return 1 + Math.floor(Math.random() * 6); }\n\n// after\nfunction rollDice(ctx) { return 1 + Math.floor(ctx.random() * 6); }","handlingStrategy":"fallback","validationCode":"// Detect the patched getter WITHOUT invoking it (property access would throw):\nconst randomIsPatched =\n  typeof Object.getOwnPropertyDescriptor(Math, 'random')?.get === 'function';","typeGuard":"function hasCtxRandom(ctx: unknown): ctx is { random(): number } {\n  return !!ctx && typeof (ctx as { random?: unknown }).random === 'function';\n}","tryCatchPattern":"function safeRandom(ctx?: { random(): number }): number {\n  try {\n    return Math.random();\n  } catch (e) {\n    if (e instanceof TypeError && /ctx\\.random/.test(e.message)) {\n      if (!ctx) throw e;\n      return ctx.random();\n    }\n    throw e;\n  }\n}","preventionTips":["Never call Math.random in module code; always take an RNG (or ctx) as a parameter","Audit dependencies for direct Math.random usage before importing them into a module","In tests, run modules under the SpacetimeDB host (not plain Node) so patched globals fail fast"],"tags":["javascript","v8","spacetimedb","determinism","rng","sandbox"],"backgroundTag":"sandboxed-api-restriction","analyzedSha":"524b4487d949b61a07d4f39c862d1290259dfd20","analyzedAt":"2026-08-16T23:58:54.611Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}