{"record":{"id":"e5971f772bff0b50","repo":"nautechsystems/nautilus_trader","slug":"expected-array-payload-e","errorCode":null,"errorMessage":"Expected array payload: {e}","messagePattern":"Expected array payload: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/okx/src/common/parse.rs","lineNumber":1364,"sourceCode":"/// Reduces code duplication by providing a common pattern for deserializing JSON arrays,\n/// parsing each message, and wrapping results in Nautilus Data enum variants.\n///\n/// # Errors\n///\n/// Returns an error if the payload is not an array or if individual messages\n/// cannot be parsed.\npub fn parse_message_vec<T, R, F, W>(\n    data: serde_json::Value,\n    parser: F,\n    wrapper: W,\n) -> anyhow::Result<Vec<Data>>\nwhere\n    T: DeserializeOwned,\n    F: Fn(&T) -> anyhow::Result<R>,\n    W: Fn(R) -> Data,\n{\n    let messages: Vec<T> =\n        serde_json::from_value(data).map_err(|e| anyhow::anyhow!(\"Expected array payload: {e}\"))?;\n\n    let mut results = Vec::with_capacity(messages.len());\n\n    for message in &messages {\n        let parsed = parser(message)?;\n        results.push(wrapper(parsed));\n    }\n\n    Ok(results)\n}\n\n/// Converts a Nautilus bar specification into the matching OKX candle channel.\n///\n/// # Errors\n///\n/// Returns an error if the provided bar specification does not have a matching\n/// OKX websocket channel.\npub fn bar_spec_as_okx_channel(bar_spec: BarSpecification) -> anyhow::Result<OKXWsChannel> {","sourceCodeStart":1346,"sourceCodeEnd":1382,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/okx/src/common/parse.rs#L1346-L1382","documentation":"parse_message_vec deserializes a serde_json::Value into Vec<T> before applying the per-message parser. The error 'Expected array payload' is raised when the JSON value is not an array (or the elements don't match T), e.g. an object or error payload from OKX.","triggerScenarios":"Calling the WebSocket-specific message parsers (ticker, quote, trade, mark/index price msg vec) with a data payload that is a JSON object or string rather than an array of channel messages.","commonSituations":"OKX pushes an error event or subscribe confirmation instead of the data array; channel data format changes; wiring the wrong event payload into parse_message_vec.","solutions":["Log the raw payload and confirm whether it is an OKX error/event message rather than a data array","Handle OKX 'event' messages (subscribe/error) before dispatching to array parsers","Check that the subscribed channel produces the expected array-of-records shape","Verify adapter/OKX API version alignment for the channel's schema"],"exampleFix":"// before\nlet reports = parse_message_vec(&data, parse_ticker_msg, Data::Ticker)?;\n// after\nif !data.is_array() {\n    tracing::warn!(?data, \"Non-array payload; skipping\");\n    return Ok(Vec::new());\n}\nlet reports = parse_message_vec(&data, parse_ticker_msg, Data::Ticker)?;","handlingStrategy":"type-guard","validationCode":"fn is_array_payload(v: &serde_json::Value) -> bool { v.is_array() }\nif !is_array_payload(&data) { /* handle OKX event/error message first */ }","typeGuard":"fn as_msg_array(v: &serde_json::Value) -> Option<&Vec<serde_json::Value>> { v.as_array() }","tryCatchPattern":"match parse_message_vec(&data, parse_ticker_msg, Data::Ticker) {\n    Ok(data_vec) => handle(data_vec),\n    Err(e) => tracing::debug!(\"non-array websocket payload ignored: {e:#}\"),\n}","preventionTips":["Route OKX 'event' (subscribe/error) messages away from data parsers before dispatch","Log raw payloads at debug level for schema mismatches","Pin the channel schema with recorded-payload regression tests"],"tags":["rust","okx","json","websocket"],"backgroundTag":"unexpected-response-shape","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}