n0-computer/iroh · error · Error

FrameTooLarge

FrameTooLarge

Error message

Frame is too large, has {frame_len} bytes

What it means

Error::FrameTooLarge is returned when decoding an inbound relay frame whose content length (frame_len) exceeds MAX_PACKET_SIZE. The relay protocol caps packet size, so any larger frame is rejected at decode time rather than processed. This indicates a malicious, buggy, or non-protocol peer.

Solutions

  1. Verify you are connected to a genuine, up-to-date iroh relay server.
  2. Check the framing layer: a misparsed length prefix can merge frames — confirm lengths are read with the right endianness/width.
  3. Drop the connection on this error; oversized frames indicate desync that cannot be recovered in-stream.
Defensive patterns

Strategy: try-catch

Validate before calling

fn plausible_frame(content: &Bytes) -> bool {
    !content.is_empty() && content.len() - 1 <= MAX_PACKET_SIZE
}

Try / catch

// Rust
match Frame::from_bytes(content, false) {
    Err(Error::FrameTooLarge { frame_len }) => {
        tracing::error!(frame_len, "oversized frame from relay — closing connection");
        conn.close(); // framing is untrusted; cannot recover in-stream
    }
    other => other?,
}

Prevention

When it happens

Trigger: Receiving a frame from a relay whose payload after the frame-type byte is longer than MAX_PACKET_SIZE and passing it to from_bytes.

Common situations: Connecting to a hostile or non-iroh server that sends oversized payloads; desynchronized framing that misreads lengths and treats multiple frames as one giant frame.

Understand the failure class

Background: payload too large / request exceeds maximum size: why libraries cap bytes and how to fix oversize payloads — this error's family across 50 libraries.

Related errors


AI-assisted analysis of n0-computer/iroh@2b4de030ce (2026-09-08). Data as JSON: /api/errors/95b5a0de0719e93a. Report an issue: GitHub.

Appendix: source

Thrown at iroh-relay/src/protos/relay.rs:403

            Self::Health { problem } => problem.len(),
        };
        self.typ().encoded_len() + payload_len
    }

    /// Tries to decode a frame received over websockets.
    ///
    /// Specifically, bytes received from a binary websocket message frame.
    ///
    /// `protocol_version` is the negotiated protocol version for this connection.
    #[allow(clippy::result_large_err)]
    pub(crate) fn from_bytes(
        mut content: Bytes,
        cache: &KeyCache,
        protocol_version: ProtocolVersion,
    ) -> Result<Self, Error> {
        let frame_type = FrameType::from_bytes(&mut content)?;
        let frame_len = content.len();
        ensure!(
            frame_len <= MAX_PACKET_SIZE,
            Error::FrameTooLarge { frame_len }
        );

        let res = match frame_type {
            FrameType::RelayToClientDatagram | FrameType::RelayToClientDatagramBatch => {
                ensure!(content.len() >= EndpointId::LENGTH, Error::InvalidFrame);

                let remote_endpoint_id = cache.key_from_slice(&content[..EndpointId::LENGTH])?;
                let datagrams = Datagrams::from_bytes(
                    content.slice(EndpointId::LENGTH..),
                    frame_type == FrameType::RelayToClientDatagramBatch,
                )?;
                Self::Datagrams {
                    remote_endpoint_id,
                    datagrams,
                }
            }

View on GitHub (pinned to 2b4de030ce)