clockworklabs/SpacetimeDB · error · Error
`fromCounterV7` requires `randomBytes.length == 4`
Error message
`fromCounterV7` requires `randomBytes.length == 4`
What it means
Uuid.fromCounterV7 builds a UUIDv7 from a 31-bit monotonic counter, a Timestamp, and caller-supplied randomness. The random bytes fill a fixed 4-byte field of the counter-v7 layout, so the method requires exactly 4 bytes and validates this first. Any other array length is rejected before the counter or timestamp are touched.
Solutions
- Pass exactly 4 fresh random bytes: crypto.getRandomValues(new Uint8Array(4))
- Check randomBytes.length === 4 before calling fromCounterV7 and fail fast with your own message
- If you do not need counter-based monotonic IDs, generate a plain random UUID instead of calling fromCounterV7
Example fix
// before const rand = crypto.getRandomValues(new Uint8Array(16)); const id = Uuid.fromCounterV7(counter, now, rand); // throws: length != 4 // after const rand = crypto.getRandomValues(new Uint8Array(4)); const id = Uuid.fromCounterV7(counter, now, rand);
Defensive patterns
Strategy: validation
Validate before calling
if (randomBytes.length !== 4) {
throw new Error(`fromCounterV7 needs exactly 4 random bytes, got ${randomBytes.length}`);
}
const id = Uuid.fromCounterV7(counter, now, randomBytes); Prevention
- Generate the 4 random bytes at the call site: crypto.getRandomValues(new Uint8Array(4))
- Wrap fromCounterV7 in one helper that enforces length, counter range and timestamp once
- Never share a random buffer between UUID generation strategies with different layouts
When it happens
Trigger: Calling Uuid.fromCounterV7(counter, now, randomBytes) where randomBytes.length is not 4: a 16-byte buffer from crypto.getRandomValues(new Uint8Array(16)), an empty array, or a wrongly-sized slice of a shared entropy pool.
Common situations: Reusing a 16-byte random buffer written for UUIDv4 code paths; porting code from another UUID library whose API takes 16 random bytes; slicing a shared randomness array with an off-by-N length.
Related errors
- `fromCounterV7` `timestamp` before unix epoch
- `fromCounterV7` uuid `counter` must be non-negative
- Invalid hex UUID
- Subscriptions must be SQL strings or typed queries
- Subscriptions must have at least one query
AI-assisted analysis of clockworklabs/SpacetimeDB@6dee26c6ef (2026-08-20).
Data as JSON: /api/errors/e226656e802ec54b.
Report an issue: GitHub.
Appendix: source
Thrown at crates/bindings-typescript/src/lib/uuid.ts:159
* ```ts
* const now = Timestamp.fromMillis(1_686_000_000_000n);
* const counter = { value: 1 };
* const randomBytes = new Uint8Array(4);
*
* const uuid = Uuid.fromCounterV7(counter, now, randomBytes);
*
* console.assert(
* uuid.toString() === "0000647e-5180-7000-8000-000200000000"
* );
* ```
*/
static fromCounterV7(
counter: { value: number },
now: Timestamp,
randomBytes: Uint8Array
): Uuid {
if (randomBytes.length !== 4) {
throw new Error('`fromCounterV7` requires `randomBytes.length == 4`');
}
if (counter.value < 0) {
throw new Error('`fromCounterV7` uuid `counter` must be non-negative');
}
if (now.__timestamp_micros_since_unix_epoch__ < 0) {
throw new Error('`fromCounterV7` `timestamp` before unix epoch');
}
// 31-bit monotonic counter with wraparound
const counterVal = counter.value;
counter.value = (counterVal + 1) & 0x7fff_ffff;
// 48-bit unix timestamp (ms)
const tsMs = now.toMillis() & 0xffff_ffff_ffffn;
const bytes = new Uint8Array(16);View on GitHub (pinned to 6dee26c6ef)