sinelaw/fresh · error

ws frame too large ( bytes)

Error message

ws frame too large ({len} bytes)

What it means

ws_parse_frame (invoked from drain_messages) parsed a WebSocket frame whose declared payload length exceeds WS_PAYLOAD_CAP. mod.rs:1307 bails to protect the editor's embedded web UI from oversized/malicious frames that could exhaust memory. The connection's frame is rejected outright.

Solutions

  1. Fix the client to split large payloads into frames within the server's size cap
  2. Raise WS_PAYLOAD_CAP if your application legitimately sends larger messages (and re-evaluate DoS exposure)
  3. Inspect who is connecting to the WebSocket port — an unexpected oversized frame usually means a non-WebSocket or hostile client

Example fix

// client side: before
ws.send(hugeJsonString); // > cap, server bails
// after
for chunk in split_into_frames(hugeJsonString, MAX_FRAME_SIZE) {
    ws.send(chunk);
}
Defensive patterns

Strategy: validation

Validate before calling

if payload.len() > WS_PAYLOAD_CAP {
    return Err(format!("payload {} exceeds server cap", payload.len()));
}

Try / catch

ws.on('error', (e) => {
  if (String(e).includes('ws frame too large')) { reconnectWithChunking(); }
});

Prevention

When it happens

Trigger: A WebSocket client sends a frame with a 64-bit extended length header whose value exceeds WS_PAYLOAD_CAP — either an attacker sending crafted frames, a buggy client, or corruption of the length prefix.

Common situations: Malicious requests against an exposed dev web-UI port; proxy/middleware mangling frame headers; a client library fragmenting or mis-framing messages.

Understand the failure class

Background: payload too large / request exceeds maximum size: why libraries cap bytes and how to fix oversize payloads — this error's family across 50 libraries.

Related errors


AI-assisted analysis of sinelaw/fresh@67894ca546 (2026-09-13). Data as JSON: /api/errors/4161cf4a1d577ab3. Report an issue: GitHub.

Appendix: source

Thrown at crates/fresh-editor/src/webui/mod.rs:1307

    let fin = buf[0] & 0x80 != 0;
    let opcode = buf[0] & 0x0F;
    let masked = buf[1] & 0x80 != 0;
    let (mut len, mut off) = ((buf[1] & 0x7F) as u64, 2usize);
    if len == 126 {
        if buf.len() < 4 {
            return Ok(None);
        }
        len = u16::from_be_bytes([buf[2], buf[3]]) as u64;
        off = 4;
    } else if len == 127 {
        if buf.len() < 10 {
            return Ok(None);
        }
        len = u64::from_be_bytes(buf[2..10].try_into().unwrap());
        off = 10;
    }
    if len > WS_PAYLOAD_CAP as u64 {
        anyhow::bail!("ws frame too large ({len} bytes)");
    }
    let mask = if masked {
        if buf.len() < off + 4 {
            return Ok(None);
        }
        let k = [buf[off], buf[off + 1], buf[off + 2], buf[off + 3]];
        off += 4;
        Some(k)
    } else {
        None
    };
    let len = len as usize;
    if buf.len() < off + len {
        return Ok(None);
    }
    let mut payload = buf[off..off + len].to_vec();
    if let Some(k) = mask {
        // Client→server frames are always masked; unmask in place.

View on GitHub (pinned to 67894ca546)