Skip to content

Websocket message exceeding 32 MiB: server logs size error, then connection abort without close handshake #4968

@emchristiansen

Description

@emchristiansen

Environment

  • SpacetimeDB version: v2.2.0
  • Image: docker.io/clockworklabs/spacetime:v2.2.0
  • Image digest: sha256:bc85c24909f92983a7912c83e9e32d0dc3726f535886f76be87ce9222d698c3f
  • Deployment: Kubernetes StatefulSet, single replica, --listen-addr=0.0.0.0:3000
  • Client: Rust SDK (spacetimedb_sdk) connecting via websocket

Observed Behavior

A Rust SDK client sends a websocket message of 70,666,292 bytes (67.4 MiB) to a SpacetimeDB
v2.2.0 server. The server rejects the message due to a size limit and aborts the websocket
connection. The client receives a ResetWithoutClosingHandshake error.

Server Logs

Timestamps are UTC, captured via kubectl logs spacetimedb-0 -n ccc. One complete
connect/reject/abort cycle around the requested observation time of 17:02:30Z:

2026-05-06T17:02:29.914527Z DEBUG crates/client-api/src/routes/subscribe.rs:241:
  websocket: New client connected from unknown ip
  with Identity c2001aeb16590eed773b52c68da872638bfc661b5849a64394836e1d603c4a9c
  and ConnectionId 942b14ad35ed27d9b415c02d8ebdcd89

2026-05-06T17:02:29.914946Z DEBUG crates/client-api/src/routes/subscribe.rs:266:
  websocket: Database accepted connection [...]; spawning ws_client_actor and ClientConnection

2026-05-06T17:02:30.271716Z  WARN crates/client-api/src/routes/subscribe.rs:893:
  Websocket receive error: Space limit exceeded: Message too long: 70666292 > 33554432

2026-05-06T17:02:30.271851Z  INFO crates/client-api/src/routes/subscribe.rs:507:
  Client connection ended: ClientActorId(c2001aeb...@942b14ad.../106)

2026-05-06T17:02:30.272115Z  WARN crates/core/src/client/client_connection.rs:734:
  websocket connection aborted for client identity `c2001aeb...603c4a9c`
  and database identity `c2001f39...29cb7830`

The same cycle repeated 118 times within the observation window (first occurrence at
2026-05-06T17:00:13.619041Z, last at 2026-05-06T17:07:52.815523Z), with the same client
identity reconnecting after each abort. The message size was 70666292 and the limit was
33554432 in every occurrence.

Server-Side Limit

The 33,554,432-byte (32 MiB) limit is set at
crates/client-api/src/routes/subscribe.rs lines 218-221 (v2.2.0 tag):

let ws_config = WebSocketConfig::default()
    .max_message_size(Some(0x2000000))
    .max_frame_size(None)
    .accept_unmasked_frames(false);

The WebSocketOptions struct in the same file
(lines 357-392)
defines the fields exposed via config.toml: ping_interval, idle_timeout,
close_handshake_timeout, and incoming_queue_length. max_message_size and max_frame_size
are not fields of that struct.

v2.2.0 Websocket Transport Change

The v2.2.0 release notes
state:

We've introduced a new v3 WebSocket transport that batches multiple logical client messages
into a single frame, cutting per-message overhead while keeping the existing message model
intact (#4761).

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions