n0-computer/iroh · error · SendError
ExceedsMaxPacketSize
ExceedsMaxPacketSize
Error message
Packet exceeds max packet size
What it means
The relay server tried to send a RelayToClientMsg to a connected client whose encoded size exceeds MAX_PACKET_SIZE. Sending is aborted in start_send before the packet hits the wire, returning SendError::ExceedsMaxPacketSize with the offending size.
Solutions
- Split the message into multiple packets so each encoded packet stays within MAX_PACKET_SIZE.
- Reduce the number of datagrams batched into a single RelayToClientMsg::Datagrams.
- Check item.encoded_len() before enqueueing and chunk accordingly.
- Compress or shrink payloads before sending over the relay.
Example fix
// before
sink.start_send(big_msg).await?; // may exceed MAX_PACKET_SIZE
// after
for chunk in chunk_by_encoded_len(big_msg, MAX_PACKET_SIZE) {
sink.start_send(chunk).await?;
} Defensive patterns
Strategy: validation
Validate before calling
fn fits_in_packet(msg: &RelayToClientMsg) -> bool { msg.encoded_len() <= MAX_PACKET_SIZE } Type guard
fn valid_packet(msg: RelayToClientMsg) -> Option<RelayToClientMsg> { (msg.encoded_len() <= MAX_PACKET_SIZE).then_some(msg) } Try / catch
match sink.start_send(item) {
Err(SendError::ExceedsMaxPacketSize { size }) => { chunk_and_resend(size); }
other => other?,
} Prevention
- Check encoded_len() before enqueueing every relay packet.
- Cap the number of datagrams batched per message.
- Add unit tests asserting max-size invariants.
- Centralize packet construction in one helper that enforces the limit.
When it happens
Trigger: Producing a RelayToClientMsg::Datagrams (or other relay-to-client message) whose encoded length is greater than MAX_PACKET_SIZE, e.g. by batching too many/large datagrams into one packet, then passing it through the client send sink.
Common situations: Applications that accumulate many datagrams before flushing, large payload batching across a relay connection, misconfigured MTU/packet-size assumptions when porting code between direct and relayed connections.
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
- ExceedsMaxPacketSize
- The relay is rate-limiting this endpoint; outbound relay…
- Invalid transport configuration
- UnexpectedUpgradeStatus
- EmptyPacket
AI-assisted analysis of n0-computer/iroh@2b4de030ce (2026-09-08).
Data as JSON: /api/errors/ff68a6494a7616de.
Report an issue: GitHub.
Appendix: source
Thrown at iroh-relay/src/server/streams.rs:132
},
/// Attempted to send an empty packet
#[error("Attempted to send empty packet")]
EmptyPacket {},
}
impl<S> Sink<RelayToClientMsg> for RelayedStream<S>
where
S: Sink<bytes::Bytes, Error = StreamError> + Unpin,
{
type Error = SendError;
fn poll_ready(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Pin::new(&mut self.inner).poll_ready(cx).map_err(Into::into)
}
fn start_send(mut self: Pin<&mut Self>, item: RelayToClientMsg) -> Result<(), Self::Error> {
let size = item.encoded_len();
ensure!(
size <= MAX_PACKET_SIZE,
SendError::ExceedsMaxPacketSize { size }
);
if let RelayToClientMsg::Datagrams { datagrams, .. } = &item {
ensure!(!datagrams.contents.is_empty(), SendError::EmptyPacket);
}
Pin::new(&mut self.inner)
.start_send(item.to_bytes().freeze())
.map_err(Into::into)
}
fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Pin::new(&mut self.inner).poll_flush(cx).map_err(Into::into)
}
fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
Pin::new(&mut self.inner).poll_close(cx).map_err(Into::into)View on GitHub (pinned to 2b4de030ce)