{"record":{"id":"70cbd4c1e2925129","repo":"vllm-project/vllm","slug":"unsupported-auxiliary-frame-s-expected-1-frame","errorCode":null,"errorMessage":"unsupported auxiliary frame(s): expected 1 frame, got {frame_count}","messagePattern":"unsupported auxiliary frame\\(s\\): expected 1 frame, got (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"rust/src/engine-core-client/src/error.rs","lineNumber":58,"sourceCode":"    EngineCoreDead,\n    #[error(\"startup handshake timed out while waiting for {stage} after {timeout:?}\")]\n    HandshakeTimeout {\n        stage: &'static str,\n        timeout: Duration,\n    },\n    #[error(\"engine input registration timed out after {timeout:?}\")]\n    InputRegistrationTimeout { timeout: Duration },\n    #[error(\"unexpected engine id in startup handshake: expected {expected:?}, got {actual:?}\")]\n    UnexpectedHandshakeIdentity { expected: Vec<u8>, actual: Vec<u8> },\n    #[error(\"unexpected startup handshake message: {message}\")]\n    UnexpectedHandshakeMessage { message: String },\n    #[error(\"unexpected non-control output on coordinator path: {message}\")]\n    UnexpectedCoordinatorOutput { message: String },\n    #[error(\"unexpected output on main dispatcher path: {message}\")]\n    UnexpectedDispatcherOutput { message: String },\n    #[error(\"coordinator requires a Python-compatible two-byte engine id, got {engine_id:?}\")]\n    UnsupportedCoordinatorEngineId { engine_id: Vec<u8> },\n    #[error(\"unsupported auxiliary frame(s): expected 1 frame, got {frame_count}\")]\n    UnsupportedAuxFrames { frame_count: usize },\n    #[error(\"external coordinator mode is not implemented yet\")]\n    UnsupportedExternalCoordinator,\n    #[error(\"unsupported field `{field}` in {context}\")]\n    UnsupportedField {\n        context: &'static str,\n        field: &'static str,\n    },\n    #[error(\"engine control channel closed unexpectedly: {message}\")]\n    ControlClosed { message: String },\n    #[error(\"request `{request_id}` is already in flight\")]\n    DuplicateRequestId { request_id: String },\n    #[error(\n        \"data parallel rank {rank} is not connected to this frontend; connected ranks: {connected_ranks:?}\"\n    )]\n    InvalidDataParallelRank {\n        rank: u32,\n        connected_ranks: Vec<u32>,","sourceCodeStart":40,"sourceCodeEnd":76,"githubUrl":"https://github.com/vllm-project/vllm/blob/c794754062d49a8fdb63ab3c5215b488b865030c/rust/src/engine-core-client/src/error.rs#L40-L76","documentation":"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).","triggerScenarios":"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.","commonSituations":"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.","solutions":["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","Check frame_count in the error to confirm how many aux frames were produced","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","Align Rust and Python versions so aux-frame splitting rules match"],"exampleFix":"// before\nlet config = EngineCoreClientConfig { msgpack_zero_copy_threshold: 1024, .. }; // many tensors spill to aux frames\n\n// after\nlet config = EngineCoreClientConfig { msgpack_zero_copy_threshold: 1 << 20, .. }; // keep tensors inline","handlingStrategy":"validation","validationCode":"fn aux_frame_count_ok(req: &mut EngineCoreRequest, threshold: usize) -> bool {\n    // dry-run the extraction the client performs before send\n    req.extract_aux_frames(threshold).len() <= 1\n}","typeGuard":"fn is_unsupported_aux_frames(e: &engine_core_client::Error) -> bool {\n    matches!(e, engine_core_client::Error::UnsupportedAuxFrames { .. })\n}","tryCatchPattern":"if let engine_core_client::Error::UnsupportedAuxFrames { frame_count } = &err {\n    tracing::warn!(frame_count, \"too many aux frames; split request or raise zero-copy threshold\");\n}","preventionTips":["Set msgpack_zero_copy_threshold high enough that typical multimodal requests keep tensors inline","Limit large tensors per request during this client stage","Track upstream support for multi-frame aux transport and upgrade both sides together"],"tags":["rust","zeromq","multimodal","aux-frames","limits"],"backgroundTag":null,"analyzedSha":"c794754062d49a8fdb63ab3c5215b488b865030c","analyzedAt":"2026-08-14T21:17:39.825Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}