actix/actix-web · error · ProtocolError
invalid control frame length ({})
Error message
invalid control frame length ({}) What it means
ProtocolError::InvalidLength(usize) (ws/mod.rs:43) is raised in frame.rs:135-137 when a Ping or Pong control frame carries a payload longer than 125 bytes. RFC 6455 §5.5 mandates control frames have a payload length <= 125 and forbids them from being fragmented. actix closes the connection with a protocol error.
Source
Thrown at actix-http/src/ws/mod.rs:42
};
/// WebSocket protocol errors.
#[derive(Debug, Display, Error, From)]
pub enum ProtocolError {
/// Received an unmasked frame from client.
#[display("received an unmasked frame from client")]
UnmaskedFrame,
/// Received a masked frame from server.
#[display("received a masked frame from server")]
MaskedFrame,
/// Encountered invalid opcode.
#[display("invalid opcode ({})", _0)]
InvalidOpcode(#[error(not(source))] u8),
/// Invalid control frame length
#[display("invalid control frame length ({})", _0)]
InvalidLength(#[error(not(source))] usize),
/// Bad opcode.
#[display("bad opcode")]
BadOpCode,
/// A payload reached size limit.
#[display("payload reached size limit")]
Overflow,
/// Continuation has not started.
#[display("continuation has not started")]
ContinuationNotStarted,
/// Received new continuation but it is already started.
#[display("received new continuation but it has already started")]
ContinuationStarted,
View on GitHub (pinned to 937960ca67)
Solutions
- Keep Ping/Pong payloads at or below 125 bytes; move large data to Text/Binary frames.
- Update the offending peer's WebSocket library to an RFC-compliant version.
- If unavoidable, terminate the connection cleanly and reconnect.
Example fix
// before: oversize ping ws.send(Message::Ping(vec![0u8; 200])) // after: keep control payload <= 125 bytes ws.send(Message::Ping(vec![0u8; 32]))
Defensive patterns
Strategy: validation
Validate before calling
// When sending Ping/Pong, enforce the 125-byte control-frame limit.
fn safe_ping(data: Vec<u8>) -> Result<Vec<u8>, &'static str> {
if data.len() > 125 { Err("control frame payload must be <= 125 bytes") }
else { Ok(data) }
} Try / catch
match ws_stream.send(Message::Ping(payload)) {
Err(ProtocolError::InvalidLength(n)) => {
log::warn!("peer sent oversize control frame ({n} bytes); closing");
ws_stream.close(Some(CloseReason::from(CloseCode::Protocol))).await.ok();
}
Err(e) => { /* handle other errors */ }
Ok(_) => {}
} Prevention
- Keep Ping/Pong payloads small (<=125 bytes); use Binary/Text for larger data.
- Update non-compliant peer libraries.
- Treat this error as non-recoverable for the connection.
When it happens
Trigger: A WebSocket peer sends a Ping or Pong frame whose payload exceeds 125 bytes (e.g. embedding a large nonce or heartbeat data). For Close frames the same length is tolerated (frame.rs:138-141 morphs them), but Ping/Pong are rejected.
Common situations: Custom heartbeat implementations that overload Ping with oversized application data, or a client library that ignores the 125-byte control-frame limit. Rare with mainstream browsers.
Related errors
- invalid opcode ({})
- unknown continuation fragment: {}
- Invalid chunk size line: Invalid Size
- Invalid chunk size linear white space
- Invalid chunk size LF
AI-assisted analysis of actix/actix-web@937960ca67 (2026-08-06).
Data as JSON: /data/errors/ef57958d653368a7.json.
Report an issue: GitHub.