clockworklabs/SpacetimeDB · error · RangeError
Timestamp is outside of the representable range of JS's Date
Error message
Timestamp is outside of the representable range of JS's Date
What it means
Timestamp.toDate() converts microseconds-since-epoch to JS Date milliseconds. The millis value must fit within +/-Number.MAX_SAFE_INTEGER (roughly +/-285,000 years); outside that, Number(millis) would silently lose precision, so the method throws RangeError instead.
Source
Thrown at crates/bindings-typescript/src/lib/timestamp.ts:110
const millis = date.getTime();
const micros = BigInt(millis) * Timestamp.MICROS_PER_MILLIS;
return new Timestamp(micros);
}
/**
* Get a `Date` representing approximately the same point in time as `this`.
*
* This method truncates to millisecond precision,
* and throws `RangeError` if the `Timestamp` is outside the range representable as a `Date`.
*/
toDate(): Date {
const micros = this.__timestamp_micros_since_unix_epoch__;
const millis = micros / Timestamp.MICROS_PER_MILLIS;
if (
millis > BigInt(Number.MAX_SAFE_INTEGER) ||
millis < BigInt(Number.MIN_SAFE_INTEGER)
) {
throw new RangeError(
"Timestamp is outside of the representable range of JS's Date"
);
}
return new Date(Number(millis));
}
/**
* Get an ISO 8601 / RFC 3339 formatted string representation of this timestamp with microsecond precision.
*
* This method preserves the full microsecond precision of the timestamp,
* and throws `RangeError` if the `Timestamp` is outside the range representable in ISO format.
*
* @returns ISO 8601 formatted string with microsecond precision (e.g., '2025-02-17T10:30:45.123456Z')
*/
toISOString(): string {
const micros = this.__timestamp_micros_since_unix_epoch__;
const millis = micros / Timestamp.MICROS_PER_MILLIS;
View on GitHub (pinned to 524b4487d9)
Solutions
- Fix the precision at the source: construct Timestamps from microseconds since the Unix epoch
- Range-check before converting and keep extreme values as Timestamp for comparisons instead of Date
- Prefer the microsecond accessors and toISOString-style formatting over Date when values may be extreme
Example fix
// before const d = ts.toDate(); // extreme micros -> RangeError // after const MAX_MS = BigInt(Number.MAX_SAFE_INTEGER); const ms = ts.__timestamp_micros_since_unix_epoch__ / 1000n; const d = ms >= -MAX_MS && ms <= MAX_MS ? ts.toDate() : null; // null => handle out-of-band
Defensive patterns
Strategy: validation
Validate before calling
const MAX_SAFE_MILLIS = BigInt(Number.MAX_SAFE_INTEGER);
function timestampToDateSafe(ts: Timestamp): Date | null {
const millis = ts.__timestamp_micros_since_unix_epoch__ / 1000n;
if (millis > MAX_SAFE_MILLIS || millis < -MAX_SAFE_MILLIS) return null;
return ts.toDate();
} Prevention
- Construct Timestamps only from microseconds since the Unix epoch
- Keep comparisons on Timestamp values; convert to Date only at the display boundary
- Add unit tests covering extreme values so precision bugs surface in CI, not production
When it happens
Trigger: Calling .toDate() on a Timestamp built from unit-confused or corrupted micros - e.g. nanoseconds passed as micros, or a value multiplied by 1000 twice - so that |micros / 1000n| exceeds 2^53-1.
Common situations: Hand-constructing Timestamps from server data in the wrong precision; BigInt arithmetic bugs (shift/multiply errors); test fixtures using sentinel values like Number.MAX_VALUE.
Related errors
- Timestamp is outside of the representable range for ISO stri
- Invalid UUID: must be between 0 and `MAX_UUID_BIGINT`
- Tried to read ${n} byte(s) at relative offset ${this.offset}
- Uint8Array is not 16 bytes long: ${array}
- Uint8Array is not 32 bytes long: [${array}]
AI-assisted analysis of clockworklabs/SpacetimeDB@524b4487d9 (2026-08-16).
Data as JSON: /api/errors/b17396404cbd8404.
Report an issue: GitHub.