{"id":"7fd4a94463244c3c","repo":"actix/actix-web","slug":"invalid-opcode","errorCode":null,"errorMessage":"invalid opcode ({})","messagePattern":"invalid opcode \\((.+?)\\)","errorType":"exception","errorClass":"ProtocolError","httpStatus":null,"severity":"error","filePath":"actix-http/src/ws/mod.rs","lineNumber":38,"sourceCode":"    codec::{Codec, Frame, Item, Message},\n    dispatcher::Dispatcher,\n    frame::Parser,\n    proto::{hash_key, CloseCode, CloseReason, OpCode},\n};\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","sourceCodeStart":20,"sourceCodeEnd":56,"githubUrl":"https://github.com/actix/actix-web/blob/937960ca67f20e14ffe2a075bf6d4593502be12c/actix-http/src/ws/mod.rs#L20-L56","documentation":"ProtocolError::InvalidOpcode(u8) (ws/mod.rs:39) is thrown by Parser::parse_metadata in frame.rs:43-45 when the low 4 bits of the first WebSocket frame byte do not map to a defined OpCode (0,1,2,8,9,10) — i.e. values 3-7 or 11-15, which RFC 6455 §11.8 reserves. It indicates a peer that is sending non-conformant frames and the connection must be torn down with a protocol error.","triggerScenarios":"A WebSocket peer (client or server) sends a frame whose opcode is reserved, e.g. opcode 3, 5, 7, 11, or 13. Observed with buggy or hand-rolled WS implementations, fuzzers, or intermediaries that corrupt the frame header.","commonSituations":"Interoperability with a non-compliant client library, corrupted frames from a misbehaving proxy, or active security fuzzing of the WS endpoint.","solutions":["Close the connection on this error; the peer is violating RFC 6455 and cannot be recovered mid-stream.","Identify the peer client library/version and replace or patch it.","If behind a reverse proxy, verify it is not corrupting WebSocket frames (disable buffering/HTTP/1.1 transformations on the Upgrade path).","Add connection-level logging of the raw first byte to confirm the opcode value."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// In a WebSocket actor, handle the protocol error and close the connection.\nmatch ws::Dispatcher::new(framed,Codec::new()).... {\n    Err(ProtocolError::InvalidOpcode(b)) => {\n        log::warn!(\"invalid ws opcode {b:#x}; closing\");\n        // drop the actor / close the connection\n    }\n    Err(other) => { /* other protocol errors */ }\n    Ok(_) => {}\n}","preventionTips":["Use a compliant WebSocket client library rather than hand-rolling frames.","Do not attempt recovery from protocol errors; close and reconnect.","Ensure reverse proxies pass WebSocket frames through unmodified."],"tags":["websocket","protocol","actix-http","peer-error"],"analyzedSha":"937960ca67f20e14ffe2a075bf6d4593502be12c","analyzedAt":"2026-08-06T01:15:46.978Z","schemaVersion":2}