clockworklabs/SpacetimeDB · critical · RangeError
Tried to read ${n} byte(s) at relative offset ${this.offset}
Error message
Tried to read ${n} byte(s) at relative offset ${this.offset}, but only ${this.remaining} byte(s) remain What it means
BinaryReader.#ensure(n) runs before fixed-size reads and after reading U32 length prefixes (e.g. readUInt8Array reads a count then ensures that many bytes remain). If offset + n exceeds the view's byteLength, it throws this RangeError: the byte stream is shorter than the type being decoded says it must be.
Source
Thrown at crates/bindings-typescript/src/lib/binary_reader.ts:43
this.offset = 0;
}
reset(input: Uint8Array | DataView) {
this.view =
input instanceof DataView
? input
: new DataView(input.buffer, input.byteOffset, input.byteLength);
this.offset = 0;
}
get remaining(): number {
return this.view.byteLength - this.offset;
}
/** Ensure we have at least `n` bytes left to read */
#ensure(n: number): void {
if (this.offset + n > this.view.byteLength) {
throw new RangeError(
`Tried to read ${n} byte(s) at relative offset ${this.offset}, but only ${this.remaining} byte(s) remain`
);
}
}
readUInt8Array(): Uint8Array {
const length = this.readU32();
this.#ensure(length);
// Return an owned copy, not a view over the reader's buffer. Decoded column
// values are handed to user code and may be retained, but the runtime reuses
// this buffer across table scans, so a view would be silently invalidated by
// the next iter()/filter(). Callers that only consume the bytes transiently
// (e.g. readString) can use readBytes directly to avoid this copy.
// https://github.com/clockworklabs/SpacetimeDB/issues/5490
return this.readBytes(length).slice();
}
readBool(): boolean {View on GitHub (pinned to 524b4487d9)
Solutions
- Verify the deployed module's schema matches the TS bindings (redeploy the module, regenerate bindings)
- Sanity-check the input length before decoding and treat any failure as a poisoned stream, not a partial row
- Do not retain or replay views over reader buffers - readUInt8Array already returns owned copies
- Catch RangeError at the message-decode boundary and resubscribe/reconnect to resynchronize
Example fix
// before
const rows = decodeUpdate(new BinaryReader(bytes)); // truncated frame -> RangeError
// after
try {
const rows = decodeUpdate(new BinaryReader(bytes));
} catch (e) {
if (e instanceof RangeError) {
// corrupt/truncated frame: drop it and resubscribe rather than continue
await resubscribe();
} else throw e;
} Defensive patterns
Strategy: try-catch
Validate before calling
function isPlausibleFrame(bytes: Uint8Array, minHeaderBytes = 4): boolean {
return bytes.byteLength >= minHeaderBytes;
}
// Note: full validation is impossible before decoding; treat this as a cheap sanity gate only. Try / catch
try {
const rows = decodeMessage(new BinaryReader(bytes));
} catch (e) {
if (e instanceof RangeError) {
// Truncated/corrupt frame or schema desync: do not partially apply rows.
logger.warn('decode overrun, resubscribing', { byteLength: bytes.byteLength });
await resubscribe();
} else {
throw e;
}
} Prevention
- Treat a decode overrun as a poisoned stream: drop the whole message and resynchronize, never apply partial rows
- Pin module and bindings versions together in CI so schema drift is caught before runtime
- Assert minimum frame lengths before decoding as a cheap early signal
When it happens
Trigger: Decoding a truncated or wrongly-sliced buffer; a U32 length prefix declaring more bytes than remain; decoding bytes produced by a module whose schema (field types/order) differs from the client's bindings; reusing a reader whose offset is already at the end.
Common situations: Version drift between the deployed SpacetimeDB module and the TS bindings; partially received or incorrectly concatenated WebSocket frames; replaying cached buffers that the runtime reuses across table scans.
Related errors
- cannot deserialize refs without a typespace
- Error while reading {typeof(T).FullName}: expected source sp
- cannot serialize refs without a typespace
- could not serialize result: object had neither a `ok` nor an
- Could not serialize sum type; unknown tag ${value.tag}
AI-assisted analysis of clockworklabs/SpacetimeDB@524b4487d9 (2026-08-16).
Data as JSON: /api/errors/037e4c7d84664850.
Report an issue: GitHub.