iced-rs/iced · error

Encode input message

Error message

Encode input message

What it means

In iced's beacon debug bridge (the client an instrumented app uses to talk to the iced debug UI), `send` frames messages by bincode-serializing a `client::Message` and treating encoder failure as fatal via `.expect("Encode input message")`. bincode's `serialize` only returns Err when the value's `Serialize` impl itself errors, so this is a protocol-invariant assertion, not a network error path.

Source

Thrown at beacon/src/client.rs:238

/// Otherwise, a default local server address will be returned.
pub fn server_address_from_env() -> String {
    const DEFAULT_ADDRESS: &str = "127.0.0.1:9167";

    std::env::var("ICED_BEACON_SERVER_ADDRESS").unwrap_or_else(|_| String::from(DEFAULT_ADDRESS))
}

async fn _connect() -> Result<net::TcpStream, io::Error> {
    log::debug!("Attempting to connect to server...");
    let stream = net::TcpStream::connect(server_address_from_env()).await?;

    stream.set_nodelay(true)?;
    stream.writable().await?;

    Ok(stream)
}

async fn send(stream: &mut net::tcp::OwnedWriteHalf, message: Message) -> Result<(), io::Error> {
    let bytes = bincode::serialize(&message).expect("Encode input message");
    let size = bytes.len() as u64;

    stream.write_all(&size.to_be_bytes()).await?;
    stream.write_all(&bytes).await?;
    stream.flush().await?;

    Ok(())
}

async fn receive(
    stream: &mut net::tcp::OwnedReadHalf,
    buffer: &mut Vec<u8>,
) -> Result<Command, Error> {
    let size = stream.read_u64().await? as usize;

    if buffer.len() < size {
        buffer.resize(size, 0);
    }

View on GitHub (pinned to 2cffa99b39)

Solutions

  1. Fix the Message payload type so bincode can encode it (proper derived Serialize/Deserialize, no fallible serializer behavior)
  2. Replace `.expect(...)` with `?` mapped into io::Error so a bad frame closes the connection instead of killing the app
  3. Add a serialize+deserialize round-trip unit test covering every protocol variant
  4. Unset ICED_BEACON_SERVER_ADDRESS or disable the debug feature to switch the bridge off while investigating

Example fix

// before
let bytes = bincode::serialize(&message).expect("Encode input message");
// after
let bytes = bincode::serialize(&message)
    .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
Defensive patterns

Strategy: validation

Validate before calling

#[test]
fn beacon_message_roundtrip() {
    for msg in all_message_variants() { // helper enumerating every client::Message
        let bytes = bincode::serialize(&msg).expect("serialize");
        let _back: Message = bincode::deserialize(&bytes).expect("deserialize");
    }
}

Prevention

When it happens

Trigger: Any debug event sent after the beacon client connects (theme change, span finished, tasks spawned, subscriptions tracked, ...) goes through `send`. The panic fires only when serialization of that specific `Message` variant fails at runtime, e.g. a payload added to the protocol whose Serialize impl errors (skipped/malformed fields, invalid enum encoding).

Common situations: Extending iced's debug protocol with a new message variant that is not cleanly bincode-serializable; mixing an app built against one iced version with a beacon/debug UI built from another so the wire types differ; running with ICED_BEACON_SERVER_ADDRESS set during development.

Related errors


AI-assisted analysis of iced-rs/iced@2cffa99b39 (2026-08-16). Data as JSON: /api/errors/cfabc727845531a3. Report an issue: GitHub.