Skip to content

Large session snapshots over the Ovis relay: the 1 MiB mux message limit needs a negotiated raise #2773

Closed

Description

@devswha

Follow-up to #2573 and #2740.

Problem

A session snapshot larger than 1 MiB cannot reach a browser over the Ovis relay. The relay mux caps one WebSocket message at 1 MiB (LIMITS_V1.max_ws_message_bytes in shared/relay-mux.ts), and WsStream.send in shared/relay-mux-engine.ts closes a larger message with 1009. Before that, VirtualSocket.send in server/relay/virtual-socket.ts counts the frame itself against OUTPUT_HARD_BYTES and closes it with 4008. A large session therefore reconnects, gets closed before its snapshot arrives, and reconnects again, every time it is opened over the relay. The same holds for a remote PC reached over the relay.

#2740 fixed this for direct connections and for remote PCs reached directly. It leaves the relay path alone on purpose.

Reproduction

  • Pair a device over the Ovis relay with a PC whose session.snapshot serializes past 1 MiB (for example about 600 panes with long cwds, as in server/core/socket.test.ts).
  • Open Ovis on that device. The terminal socket closes with 4008 ("terminal output transport stalled") from VirtualSocket.send, and with 1009 from the mux if that check is bypassed. No snapshot arrives.
  • At the code level: WsStream.send with a string over 1,048,576 bytes returns 0 and closes the stream with 1009, and decodeFrame rejects a WS_DATA START frame whose total_message_bytes is above the limit.

Why this needs a versioned negotiation

limits() in shared/relay-mux.ts requires every v1 limit in HELLO/WELCOME to equal LIMITS_V1 exactly, so a peer that sends a different value is refused with protocol_error. Raising the constant in one build would make that build refuse every phone app, hosted shell and server still on the old value, so mixed versions could not connect over the relay at all. The limit can only move behind something both ends negotiate, for example:

  • a mux feature in the HELLO features list (such as large-ws-messages) that raises the per-message cap, and the receiver's inbound reservation, only when both peers announce it; or
  • a v2 limits block both ends must support, with v1 kept as the fallback.

Either way, the 12 MiB inbound reservation bound in docs/relay-mux-limits.md has to account for the larger message, and VirtualSocket.send then needs the same excused-frame rule as server/core/connections.ts (#2740).

Activity

  1. added a commit that references this issue on Nov 5, 2026
    f32f76b
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions