actix/actix-web · error · ProtocolError
Invalid control frame length ({})
Error message
Invalid control frame length ({}) What it means
This is `ws::ProtocolError::InvalidLength(usize)` from actix-http's WebSocket module. RFC 6455 forbids control frames (ping, pong, close) from having a payload longer than 125 bytes, and actix-http's parser raises this error when a control frame exceeds that limit. It indicates the remote peer produced a spec-violating frame.
Source
Thrown at actix-http/src/ws/mod.rs:48
#[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),
// TODO(semver-major):
// /// Received a frame with non-zero reserved bits.
// #[display("Received a frame with non-zero reserved bits")]
// InvalidReservedBits,
//
/// Invalid control frame length
#[display("Invalid control frame length ({})", _0)]
InvalidLength(#[error(not(source))] usize),
// TODO(semver-major): use in Parser::try_parse_close_payload
//
// /// Invalid close status code.
// #[display("Invalid close status code ({})", _0)]
// InvalidCloseCode(#[error(not(source))] u16),
//
// /// Invalid UTF-8 close reason.
// #[display("Invalid UTF-8 close reason")]
// InvalidCloseReason,
//
/// Bad opcode.
#[display("Bad opcode")]
BadOpCode,
/// A payload reached size limit.
#[display("Payload reached size limit")]
Overflow,View on GitHub (pinned to c215607f4b)
Solutions
- Fix the peer implementation to keep control frame payloads at 125 bytes or fewer (truncate close reasons/ping payloads).
- On the actix side, keep `ws::Client`/ping payloads small; do not attach large data to ping frames.
- Treat the error as a fatal protocol violation: close the connection with CloseCode::Protocol rather than attempting to continue.
- If you control both ends, capture the reported length value to confirm the size rule that is being violated before patching the peer.
Example fix
// before
let payload = reason.as_bytes(); // could exceed 125 bytes
ws.close(Some(CloseReason { code: CloseCode::Normal, description: Some(reason) }));
// after
let description = if reason.len() > 123 { &reason[..123] } else { &reason[..] };
ws.close(Some(CloseReason { code: CloseCode::Normal, description: Some(description.to_string()) })); Defensive patterns
Strategy: validation
Validate before calling
fn control_frame_payload_ok(opcode: u8, len: usize) -> bool {
!matches!(opcode, 0x8 | 0x9 | 0xA) || len <= 125
} Type guard
fn is_control_frame(opcode: u8) -> bool {
matches!(opcode, 0x8 | 0x9 | 0xA)
} Try / catch
match result {
Err(ProtocolError::InvalidLength(n)) => {
log::warn!("control frame payload of {n} bytes exceeds 125; closing");
close_with(CloseCode::Protocol);
}
other => handle(other),
} Prevention
- Truncate close-reason text to <=123 bytes and ping payloads to <=125 bytes before sending
- Never fragment control frames; send them unfragmented with FIN=1
- Add unit tests that assert control-frame size limits in your ws client code
- Reject oversized payloads at the application boundary before wrapping them in control frames
When it happens
Trigger: Parser::parse encounters a control frame (opcode 0x8/0x9/0xA) whose payload length field is > 125 bytes.
Common situations: Interoperating with a custom WebSocket client that fragments or oversizes pings/pongs, a buggy library sending large close reasons without truncation, or a test harness generating oversized control frames.
Understand the failure class
Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.
Related errors
- Invalid opcode ({})
- Received a frame with non-zero reserved bits
- invalid opcode ({})
- invalid control frame length ({})
- unknown continuation fragment: {}
AI-assisted analysis of actix/actix-web@c215607f4b (2026-09-09).
Data as JSON: /api/errors/4a69089bfea0428d.
Report an issue: GitHub.