{"id":"ef57958d653368a7","repo":"actix/actix-web","slug":"invalid-control-frame-length","errorCode":null,"errorMessage":"invalid control frame length ({})","messagePattern":"invalid control frame length \\((.+?)\\)","errorType":"exception","errorClass":"ProtocolError","httpStatus":null,"severity":"error","filePath":"actix-http/src/ws/mod.rs","lineNumber":42,"sourceCode":"};\n\n/// WebSocket protocol errors.\n#[derive(Debug, Display, Error, From)]\npub enum ProtocolError {\n    /// Received an unmasked frame from client.\n    #[display(\"received an unmasked frame from client\")]\n    UnmaskedFrame,\n\n    /// Received a masked frame from server.\n    #[display(\"received a masked frame from server\")]\n    MaskedFrame,\n\n    /// Encountered invalid opcode.\n    #[display(\"invalid opcode ({})\", _0)]\n    InvalidOpcode(#[error(not(source))] u8),\n\n    /// Invalid control frame length\n    #[display(\"invalid control frame length ({})\", _0)]\n    InvalidLength(#[error(not(source))] usize),\n\n    /// Bad opcode.\n    #[display(\"bad opcode\")]\n    BadOpCode,\n\n    /// A payload reached size limit.\n    #[display(\"payload reached size limit\")]\n    Overflow,\n\n    /// Continuation has not started.\n    #[display(\"continuation has not started\")]\n    ContinuationNotStarted,\n\n    /// Received new continuation but it is already started.\n    #[display(\"received new continuation but it has already started\")]\n    ContinuationStarted,\n","sourceCodeStart":24,"sourceCodeEnd":60,"githubUrl":"https://github.com/actix/actix-web/blob/937960ca67f20e14ffe2a075bf6d4593502be12c/actix-http/src/ws/mod.rs#L24-L60","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: oversize ping\nws.send(Message::Ping(vec![0u8; 200]))\n\n// after: keep control payload <= 125 bytes\nws.send(Message::Ping(vec![0u8; 32]))","handlingStrategy":"validation","validationCode":"// When sending Ping/Pong, enforce the 125-byte control-frame limit.\nfn safe_ping(data: Vec<u8>) -> Result<Vec<u8>, &'static str> {\n    if data.len() > 125 { Err(\"control frame payload must be <= 125 bytes\") }\n    else { Ok(data) }\n}","typeGuard":null,"tryCatchPattern":"match ws_stream.send(Message::Ping(payload)) {\n    Err(ProtocolError::InvalidLength(n)) => {\n        log::warn!(\"peer sent oversize control frame ({n} bytes); closing\");\n        ws_stream.close(Some(CloseReason::from(CloseCode::Protocol))).await.ok();\n    }\n    Err(e) => { /* handle other errors */ }\n    Ok(_) => {}\n}","preventionTips":["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."],"tags":["websocket","protocol","actix-http","peer-error"],"analyzedSha":"937960ca67f20e14ffe2a075bf6d4593502be12c","analyzedAt":"2026-08-06T01:15:46.978Z","schemaVersion":2}