clockworklabs/SpacetimeDB · error · RangeError
Timestamp is outside of the representable range for ISO stri
Error message
Timestamp is outside of the representable range for ISO string formatting
What it means
Timestamp.toISOString() formats with full microsecond precision by reusing new Date(Number(millis)).toISOString() and replacing the millisecond digits with the microsecond remainder. The same safe-integer guard as toDate applies: millis beyond +/-Number.MAX_SAFE_INTEGER cannot round-trip through a Date without losing precision, so it throws RangeError.
Source
Thrown at crates/bindings-typescript/src/lib/timestamp.ts:133
}
/**
* 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;
if (
millis > BigInt(Number.MAX_SAFE_INTEGER) ||
millis < BigInt(Number.MIN_SAFE_INTEGER)
) {
throw new RangeError(
'Timestamp is outside of the representable range for ISO string formatting'
);
}
const date = new Date(Number(millis));
const isoBase = date.toISOString(); // Format: '2025-02-17T10:30:45.123Z'
// Extract the full 6 decimal places of microseconds
const microsRemainder = Math.abs(Number(micros % 1000000n));
const fractionalPart = String(microsRemainder).padStart(6, '0');
// Replace the 3-digit millisecond part with the full 6-digit microsecond part
return isoBase.replace(/\.\d{3}Z$/, `.${fractionalPart}Z`);
}
since(other: Timestamp): TimeDuration {
return new TimeDuration(
this.__timestamp_micros_since_unix_epoch__ -View on GitHub (pinned to 524b4487d9)
Solutions
- Fix the precision at the source: microseconds since the Unix epoch
- Range-check millis before formatting and fall back to raw micros in the display string
- Keep comparisons on Timestamp values instead of round-tripping through Date/ISO strings
Example fix
// before
const s = ts.toISOString(); // extreme micros -> RangeError
// after
const MAX_MS = BigInt(Number.MAX_SAFE_INTEGER);
const ms = ts.__timestamp_micros_since_unix_epoch__ / 1000n;
const s = ms >= -MAX_MS && ms <= MAX_MS
? ts.toISOString()
: `${ts.__timestamp_micros_since_unix_epoch__}us`; // lossless fallback Defensive patterns
Strategy: validation
Validate before calling
const MAX_SAFE_MILLIS = BigInt(Number.MAX_SAFE_INTEGER);
function timestampToIsoSafe(ts: Timestamp): string {
const millis = ts.__timestamp_micros_since_unix_epoch__ / 1000n;
if (millis > MAX_SAFE_MILLIS || millis < -MAX_SAFE_MILLIS) {
return `${ts.__timestamp_micros_since_unix_epoch__}us`;
}
return ts.toISOString();
} Prevention
- Fix units at the ingest boundary rather than guarding every formatter
- Range-check before formatting when input sources are untrusted
- Prefer microsecond accessors over ISO strings for machine-to-machine exchange
When it happens
Trigger: Calling .toISOString() on a Timestamp whose micros, divided by 1000n, fall outside +/-2^53-1 - typically unit-confused input (millis multiplied by 1e6 twice) or corrupted values.
Common situations: Formatting timestamps received from feeds with different epochs or units; BigInt arithmetic bugs; log/audit code that assumes every timestamp is 21st-century.
Related errors
- Timestamp is outside of the representable range of JS's Date
- 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/570e20009c6a361d.
Report an issue: GitHub.