{"record":{"id":"3e9d28d5de43b77a","repo":"nautechsystems/nautilus_trader","slug":"invalid-tcbbomsg-expected-trade-action-was-ac","errorCode":null,"errorMessage":"Invalid `TcbboMsg`: expected trade action, was {action}","messagePattern":"Invalid `TcbboMsg`: expected trade action, was (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/databento/src/decode/market_data.rs","lineNumber":632,"sourceCode":"\n/// Decodes a Databento TCBBO (Consolidated Top of Book with Trade) message.\n///\n/// Returns `None` for the quote if either bid or ask price is undefined (`i64::MAX`).\n/// The trade is always returned.\n///\n/// # Errors\n///\n/// Returns an error if decoding the TCBBO message fails.\npub fn decode_tcbbo_msg(\n    msg: &dbn::TcbboMsg,\n    instrument_id: InstrumentId,\n    price_precision: u8,\n    ts_init: Option<UnixNanos>,\n) -> anyhow::Result<(Option<QuoteTick>, TradeTick)> {\n    let (maybe_quote, maybe_trade) =\n        decode_cmbp1_msg(msg, instrument_id, price_precision, ts_init, true)?;\n    let trade = maybe_trade.ok_or_else(|| {\n        anyhow::anyhow!(\n            \"Invalid `TcbboMsg`: expected trade action, was {}\",\n            msg.action as u8 as char\n        )\n    })?;\n\n    Ok((maybe_quote, trade))\n}\n\n/// # Errors\n///\n/// Returns an error if `rtype` is not a supported bar aggregation.\npub fn decode_bar_type(\n    msg: &dbn::OhlcvMsg,\n    instrument_id: InstrumentId,\n) -> anyhow::Result<BarType> {\n    let bar_type = match msg.hd.rtype {\n        32 => {\n            // ohlcv-1s","sourceCodeStart":614,"sourceCodeEnd":650,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/databento/src/decode/market_data.rs#L614-L650","documentation":"decode_tcbbo_msg decodes a TCBB0/TcbboMsg into a quote and a trade tick, delegating to decode_cmbp1_msg. The CMBP-1 record may carry non-trade actions (e.g. book refreshes); since TCBB0 decoding requires a trade action, a record without a trade component is rejected with this error.","triggerScenarios":"Calling decode_tcbbo_msg on a TcbboMsg whose msg.action is not a trade action (so decode_cmbp1_msg returns None for the trade), e.g. book-clearing/refresh records interleaved in a TCBB0 stream.","commonSituations":"Replaying TCBB0 historical data containing non-trade action records; decoding combined feed records where action='R' or similar book events appear; pipeline code that should filter actions before decode.","solutions":["Filter records by msg.action before calling decode_tcbbo_msg, skipping non-trade actions","Use the CMBP-1 decoder (decode_cmbp1_msg) directly to handle both quote and non-trade actions gracefully","Upgrade the adapter in case newer versions tolerate non-trade TCBB0 records","Inspect msg.action on offending records to confirm they are book events, not trades"],"exampleFix":"// before\nlet (quote, trade) = decode_tcbbo_msg(&msg, instrument_id, precision, None)?;\n// after\nif msg.action != b'T' { return Ok(None); } // skip non-trade records\nlet (quote, trade) = decode_tcbbo_msg(&msg, instrument_id, precision, None)?;","handlingStrategy":"validation","validationCode":"// Rust\nif msg.action != b'T' { return Ok(None); }","typeGuard":null,"tryCatchPattern":"// Rust\nErr(e) => log::debug(\"skip: {e:#}\"),","preventionTips":["Filter by action","Inspect dataset actions","Use cmbp1 decoder","Track adapter updates"],"tags":["rust","databento","tcbbo","decode"],"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-14T05:17:10.506Z"}