vllm-project/vllm · error · Error

io error

Error message

io error

What it means

Error::Io is the #[from] wrapper for std::io::Error inside the crate's unified error enum. Any I/O failure inside the client (socket option errors, fd errors from the ZMQ layer surfaced as io::Error, spawn/read failures) is folded into this variant, so the Display text 'io error' alone is intentionally terse — the source chain holds the real cause.

Source

Thrown at rust/src/engine-core-client/src/error.rs:33

#[derive(Debug, Error, Macro)]
pub enum Error {
    #[error("messagepack encode failed for {target_type}: {message}")]
    Encode {
        target_type: &'static str,
        message: String,
    },
    #[error("messagepack decode failed for {target_type}: {message}")]
    Decode {
        target_type: &'static str,
        message: String,
    },
    #[error("messagepack value decode failed")]
    ValueDecode(#[from] rmpv::decode::Error),
    #[error("messagepack ext value decode failed: {message}")]
    ExtValueDecode { message: String },
    #[error("invalid structured outputs params: {message}")]
    InvalidStructuredOutputsParams { message: String },
    #[error("io error")]
    Io(#[from] std::io::Error),
    #[error("transport error")]
    Transport(#[from] zeromq::ZmqError),
    #[error("ZMQ runtime task failed")]
    ZmqRuntimeTask(#[from] tokio::task::JoinError),
    #[error("engine core reported fatal failure")]
    EngineCoreDead,
    #[error("startup handshake timed out while waiting for {stage} after {timeout:?}")]
    HandshakeTimeout {
        stage: &'static str,
        timeout: Duration,
    },
    #[error("engine input registration timed out after {timeout:?}")]
    InputRegistrationTimeout { timeout: Duration },
    #[error("unexpected engine id in startup handshake: expected {expected:?}, got {actual:?}")]
    UnexpectedHandshakeIdentity { expected: Vec<u8>, actual: Vec<u8> },
    #[error("unexpected startup handshake message: {message}")]
    UnexpectedHandshakeMessage { message: String },

View on GitHub (pinned to c794754062)

Solutions

  1. Inspect the error chain (err.source() / {:?} debug print) — the io::Error kind and message identify the real failure
  2. Check fd limits (ulimit -n) when running many engines
  3. Verify IPC/tcp bind paths and permissions if it occurs during connect
  4. File an issue with the full chain if the underlying io::Error is unclear from the code path

Example fix

// before
match client_result {
    Err(e) => log::error!("failed: {e}"), // prints only 'io error'
}

// after
match client_result {
    Err(e) => {
        let mut chain = e.to_string();
        let mut src = std::error::Error::source(&e);
        while let Some(s) = src { chain.push_str(&format!(": {s}")); src = s.source(); }
        log::error!("failed: {chain}");
    }
}
Defensive patterns

Strategy: try-catch

Type guard

fn is_io_error(e: &engine_core_client::Error) -> bool {
    matches!(e, engine_core_client::Error::Io(_))
}

Try / catch

if let engine_core_client::Error::Io(io) = &err {
    tracing::error!(kind = ?io.kind(), %io, "io failure"); // unwrap the source for real diagnostics
}

Prevention

When it happens

Trigger: Any ? conversion from a std::io::Result inside engine-core-client: binding helpers, ZMQ socket operations that report io errors, or task plumbing. Unlike Transport (zeromq::ZmqError), this fires on plain OS-level I/O problems.

Common situations: File descriptor exhaustion after opening many engine sockets, permission errors on IPC paths, or an OS-level broken pipe surfacing outside the zeromq error type. Because Display hides the cause, users often misdiagnose it; always inspect the error source.

Related errors


AI-assisted analysis of vllm-project/vllm@c794754062 (2026-08-14). Data as JSON: /api/errors/a228f8a41d489b09. Report an issue: GitHub.