actix/actix-web · error · ProtocolError

invalid opcode ({})

Error message

invalid opcode ({})

What it means

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.

Source

Thrown at actix-http/src/ws/mod.rs:38

    codec::{Codec, Frame, Item, Message},
    dispatcher::Dispatcher,
    frame::Parser,
    proto::{hash_key, CloseCode, CloseReason, OpCode},
};

/// 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,

View on GitHub (pinned to 937960ca67)

Solutions

  1. Close the connection on this error; the peer is violating RFC 6455 and cannot be recovered mid-stream.
  2. Identify the peer client library/version and replace or patch it.
  3. If behind a reverse proxy, verify it is not corrupting WebSocket frames (disable buffering/HTTP/1.1 transformations on the Upgrade path).
  4. Add connection-level logging of the raw first byte to confirm the opcode value.
Defensive patterns

Strategy: try-catch

Try / catch

// In a WebSocket actor, handle the protocol error and close the connection.
match ws::Dispatcher::new(framed,Codec::new()).... {
    Err(ProtocolError::InvalidOpcode(b)) => {
        log::warn!("invalid ws opcode {b:#x}; closing");
        // drop the actor / close the connection
    }
    Err(other) => { /* other protocol errors */ }
    Ok(_) => {}
}

Prevention

When it happens

Trigger: 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.

Common situations: Interoperability with a non-compliant client library, corrupted frames from a misbehaving proxy, or active security fuzzing of the WS endpoint.

Related errors


AI-assisted analysis of actix/actix-web@937960ca67 (2026-08-06). Data as JSON: /data/errors/7fd4a94463244c3c.json. Report an issue: GitHub.