vllm-project/vllm · error · Error

unsupported auxiliary frame(s): expected 1 frame, got {frame

Error message

unsupported auxiliary frame(s): expected 1 frame, got {frame_count}

What it means

Error::UnsupportedAuxFrames { frame_count } reports that a request or message carried an auxiliary-frame count other than the single frame the current protocol supports: 'expected 1 frame, got {frame_count}'. Aux frames are the zero-copy mechanism that moves large tensors (multimodal embeddings, request tensors exceeding msgpack_zero_copy_threshold) out of the msgpack body into trailing ZMQ frames (protocol/request.rs extract_aux_frames, transport.rs:534-538 assembles 3 + aux frames).

Source

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

    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,
    },
    #[error("engine control channel closed unexpectedly: {message}")]
    ControlClosed { message: String },
    #[error("request `{request_id}` is already in flight")]
    DuplicateRequestId { request_id: String },
    #[error(
        "data parallel rank {rank} is not connected to this frontend; connected ranks: {connected_ranks:?}"
    )]
    InvalidDataParallelRank {
        rank: u32,
        connected_ranks: Vec<u32>,

View on GitHub (pinned to c794754062)

Solutions

  1. Reduce the number of large tensors per request, or raise msgpack_zero_copy_threshold so tensors stay inline in msgpack instead of becoming aux frames
  2. Check frame_count in the error to confirm how many aux frames were produced
  3. If multiple aux frames are legitimately needed, this is a known limitation of the current client stage — track the upstream implementation and update both sides together
  4. Align Rust and Python versions so aux-frame splitting rules match

Example fix

// before
let config = EngineCoreClientConfig { msgpack_zero_copy_threshold: 1024, .. }; // many tensors spill to aux frames

// after
let config = EngineCoreClientConfig { msgpack_zero_copy_threshold: 1 << 20, .. }; // keep tensors inline
Defensive patterns

Strategy: validation

Validate before calling

fn aux_frame_count_ok(req: &mut EngineCoreRequest, threshold: usize) -> bool {
    // dry-run the extraction the client performs before send
    req.extract_aux_frames(threshold).len() <= 1
}

Type guard

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

Try / catch

if let engine_core_client::Error::UnsupportedAuxFrames { frame_count } = &err {
    tracing::warn!(frame_count, "too many aux frames; split request or raise zero-copy threshold");
}

Prevention

When it happens

Trigger: A message arrives with more than one aux frame attached — i.e. a request containing multiple large tensors that each crossed the zero-copy threshold, or a peer that batches aux frames differently than this client accepts. The variant is currently defined in the enum as the guard for this frame-count contract on aux-frame-aware paths.

Common situations: Multimodal requests with several large embedding tensors (multiple images/video frames) each extracted into their own aux frame, exceeding the 1-frame limit of the current implementation stage. Also version mismatch if the Python side emits multiple aux frames where the Rust stage expects one.

Related errors


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