Ramonda

RMD021 — A random number was read while a value was being derived

Math.random(), crypto.randomUUID() and crypto.getRandomValues() are reported when they are called while one of the four pure phases is running. The same call fails differently in each, so the message differs with it:

  • In a render() the output depends on when it ran, so a server render and its hydration disagree and the markup is thrown away (RMD007).
  • In a @compute it is quieter and worse: the answer is cached, so the value is frozen at the moment it was first asked for, and only a dependency the compute actually READ can refresh it — which may be never.
  • In a @memoized builder it is cached with the handler, keyed by the arguments, so every call to that handler uses the one value. The builder runs during a render, so without its own report the fix would look like a render problem.
  • In a hook's props callback it is the strangest of the four. The callback is cached on the signals it reads, and a random or clock value is not one of them — so it is frozen into the bag until something unrelated invalidates the callback, and then it jumps. As a query key: an entry that changes when somebody else's state moves, and never when yours does.

Read it once in @created and keep it in @state (or @persist, so it survives hydration), take it as a prop, or read it in the event handler that needs it.

The clock is deliberately not watched here. The platform reads it behind your back — an Event constructor stamps timeStamp — so a guard on it would report calls your app never made, attributed to whichever component happened to be rendering. new Date() is caught by RMD020 as a fresh identity, and Date.now() only when a hydration disagrees (RMD007). In a client-only app nothing catches it at runtime, which is why ramonda-check reads it out of the source instead, as clock-read-while-rendering.

Next