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
- Inspect the error chain (err.source() / {:?} debug print) — the io::Error kind and message identify the real failure
- Check fd limits (ulimit -n) when running many engines
- Verify IPC/tcp bind paths and permissions if it occurs during connect
- 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
- Always log the full error chain; 'io error' Display is intentionally terse
- Raise ulimit -n before running many engines
- Monitor fd usage and socket counts in long-running frontends
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
- failed to read chat template file
- {kind} parser `{name}` is not registered{}
- failed to initialize {kind} parser `{name}`
- gpt_oss uses native Harmony output parsing; generic {kind} p
- harmony output parsing failed
AI-assisted analysis of vllm-project/vllm@c794754062 (2026-08-14).
Data as JSON: /api/errors/a228f8a41d489b09.
Report an issue: GitHub.