actix/actix-web · error · ProtocolError

Unknown continuation fragment

Error message

Unknown continuation fragment: {}

What it means

This is `ws::ProtocolError::ContinuationFragment(OpCode)` from actix-http's WebSocket handling. A fragmented message must consist of a first frame (text/binary) followed only by continuation frames (opcode 0x0). This error is raised when a continuation frame arrives when no fragmented message is in progress, i.e. the fragment sequence state machine is out of sync.

Solutions

  1. Fix the sending side so every fragmented message starts with an initial text/binary frame (FIN=0) before any continuation frames.
  2. Ensure only the last fragment has FIN=1 and that no extra continuation frames are sent after it.
  3. Check for intermediaries (proxies/load balancers) that could reorder or duplicate WebSocket frames and bypass or replace them.
  4. On error, reset the per-connection message state and close with CloseCode::Protocol; do not attempt to salvage the partial message.

Example fix

// before: sender starts fragments with opcode 0x0
send_frame(Frame::continuation(payload).fin(false));
// after: first fragment must carry the message type
send_frame(Frame::text(payload).fin(false));
send_frame(Frame::continuation(rest).fin(true));
Defensive patterns

Strategy: try-catch

Validate before calling

// sender-side check before emitting a continuation frame
if (!fragmentationActive) throw new Error("continuation frame without an open fragmented message");

Type guard

struct FragmentState { in_progress: bool }
fn can_send_continuation(state: &FragmentState) -> bool {
    state.in_progress
}

Try / catch

match result {
    Err(ProtocolError::ContinuationFragment(op)) => {
        log::warn!("unexpected continuation fragment (op {:?}); resetting message state", op);
        reset_assembler();
        close_with(CloseCode::Protocol);
    }
    other => handle(other),
}

Prevention

When it happens

Trigger: The ws message assembler receives a continuation frame (opcode 0x0) while `continuation` state is None/finished — e.g. a lone continuation frame or a continuation after the FIN frame already closed the message.

Common situations: A peer that emits continuation frames without a preceding fragmented text/binary frame, double-sending the final fragment, a proxy reordering/dropping frames, or resuming a session mid-message after reconnecting.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of actix/actix-web@c215607f4b (2026-09-09). Data as JSON: /api/errors/30027b0d1c1dd7e6. Report an issue: GitHub.

Appendix: source

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

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

    /// Unknown continuation fragment.
    #[display("Unknown continuation fragment: {}", _0)]
    ContinuationFragment(#[error(not(source))] OpCode),

    /// I/O error.
    #[display("I/O error: {}", _0)]
    Io(io::Error),
}

/// WebSocket handshake errors
#[derive(Debug, Clone, Copy, PartialEq, Eq, Display, Error)]
pub enum HandshakeError {
    /// Only get method is allowed.
    #[display("method not allowed")]
    GetMethodRequired,

    /// Upgrade header if not set to WebSocket.
    #[display("WebSocket upgrade is expected")]
    NoWebsocketUpgrade,

    /// Connection header is not set to upgrade.

View on GitHub (pinned to c215607f4b)