← 1.0.0 scope ISS-38

“Your answer does not fit” and “the server died” arrive as the same thing

Status
Open
Found while
the first benchmark under a small VPS's memory limit
Triage
Fix in 1.0.0
Component
server, protocol

What was measured

Asking for more rows than fit in a 16 MiB frame, and asking for so many that the server was OOM-killed, produced the same thing at the client both times: a bare EOF. The benchmark rig can only tell the two apart by redialling — if the dial succeeds the server merely hung up, if it is refused the process is gone. Every client would have to do the same, and a client that does not do it reports a crash where there was a refusal.

Why it happens

The cap is enforced in protocol.Encode, which returns ErrPayloadTooLarge. The server's send path passes that error straight up:

func write(conn io.Writer, frame protocol.Frame, payload []byte) error {
	frame.Version = protocol.Version
	frame.Payload = payload

	encoded, err := protocol.Encode(frame)
	if err != nil {
		return err
	}

There is nowhere left to put the refusal. The one channel for telling a client anything is a frame, and the failure being reported is that a frame could not be made. So the connection closes, and closing a connection is the one signal that carries no information.

This matters more than it looks, because this project already decided that a refusal is not prose. failure() in the server carries a message and a code, with the reason written down next to it: a client that only receives prose cannot act on it, and telling refusals apart by matching strings is how a driver breaks when a server improves its wording. ISS-21 exists because one refusal reached a caller as "failed". This is the same principle failing at the one point where the mechanism for codes cannot be used.

What closing it would mean

Out of scope

Conditions

Measured 2026-09-21 on 737e149, 2 KB rows, plaintext TCP, one connection. The behaviour is in the code path above and does not depend on the container limits — the benchmark is how it was noticed, not what makes it true.