vllm-project/vllm · error · Error

unexpected engine id in startup handshake: expected {expecte

Error message

unexpected engine id in startup handshake: expected {expected:?}, got {actual:?}

What it means

Error::UnexpectedHandshakeIdentity carries expected and actual engine id bytes and is raised by decode_handshake_message (transport.rs:420-427) when a handshake frame arrives with a ZMQ routing identity different from the one expected in contexts where the peer identity is already pinned (expected_id is Some).

Source

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

    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 },
    #[error("unexpected non-control output on coordinator path: {message}")]
    UnexpectedCoordinatorOutput { message: String },
    #[error("unexpected output on main dispatcher path: {message}")]
    UnexpectedDispatcherOutput { message: String },
    #[error("coordinator requires a Python-compatible two-byte engine id, got {engine_id:?}")]
    UnsupportedCoordinatorEngineId { engine_id: Vec<u8> },
    #[error("unsupported auxiliary frame(s): expected 1 frame, got {frame_count}")]
    UnsupportedAuxFrames { frame_count: usize },
    #[error("external coordinator mode is not implemented yet")]
    UnsupportedExternalCoordinator,
    #[error("unsupported field `{field}` in {context}")]
    UnsupportedField {
        context: &'static str,
        field: &'static str,
    },

View on GitHub (pinned to c794754062)

Solutions

  1. Compare expected vs actual byte arrays: identical ids from two sources = duplicate engine id configuration
  2. Ensure each engine derives a unique identity (engine index/rank) and no ids collide across the fleet
  3. Tear down stale sockets/processes from previous runs before reconnecting
  4. If an engine legitimately restarted, restart the frontend client too so identity expectations reset
Defensive patterns

Strategy: validation

Validate before calling

fn unique_engine_ids(ids: &[Vec<u8>]) -> bool {
    let mut seen = std::collections::HashSet::new();
    ids.iter().all(|id| seen.insert(id.clone()))
}

Type guard

fn is_identity_mismatch(e: &engine_core_client::Error) -> bool {
    matches!(e, engine_core_client::Error::UnexpectedHandshakeIdentity { .. })
}

Try / catch

if let engine_core_client::Error::UnexpectedHandshakeIdentity { expected, actual } = &err {
    tracing::error!(?expected, ?actual, "engine identity collision; restart frontend with clean identity set");
}

Prevention

When it happens

Trigger: Receiving a handshake message on a socket where the frontend already knows the engine's identity, but frames[0] (the ZMQ identity frame) does not match — e.g. a duplicate or misconfigured engine reusing another engine's socket, or an engine restarted with a fresh identity while stale registrations are still in flight.

Common situations: Two engines configured with the same engine id (copy-paste of worker configs), a restarted engine whose identity changed while the frontend still expects the old one, or leftover sockets from a previous cluster run still sending frames. The expected/got byte arrays in the message directly show the collision.

Understand the failure class

Related errors


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