nautechsystems/nautilus_trader · error · anyhow::Error
Invalid `TcbboMsg`: expected trade action, was {action}
Error message
Invalid `TcbboMsg`: expected trade action, was {action} What it means
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.
Source
Thrown at crates/adapters/databento/src/decode/market_data.rs:632
/// Decodes a Databento TCBBO (Consolidated Top of Book with Trade) message.
///
/// Returns `None` for the quote if either bid or ask price is undefined (`i64::MAX`).
/// The trade is always returned.
///
/// # Errors
///
/// Returns an error if decoding the TCBBO message fails.
pub fn decode_tcbbo_msg(
msg: &dbn::TcbboMsg,
instrument_id: InstrumentId,
price_precision: u8,
ts_init: Option<UnixNanos>,
) -> anyhow::Result<(Option<QuoteTick>, TradeTick)> {
let (maybe_quote, maybe_trade) =
decode_cmbp1_msg(msg, instrument_id, price_precision, ts_init, true)?;
let trade = maybe_trade.ok_or_else(|| {
anyhow::anyhow!(
"Invalid `TcbboMsg`: expected trade action, was {}",
msg.action as u8 as char
)
})?;
Ok((maybe_quote, trade))
}
/// # Errors
///
/// Returns an error if `rtype` is not a supported bar aggregation.
pub fn decode_bar_type(
msg: &dbn::OhlcvMsg,
instrument_id: InstrumentId,
) -> anyhow::Result<BarType> {
let bar_type = match msg.hd.rtype {
32 => {
// ohlcv-1sView on GitHub (pinned to 18893faf8b)
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
Example fix
// before
let (quote, trade) = decode_tcbbo_msg(&msg, instrument_id, precision, None)?;
// after
if msg.action != b'T' { return Ok(None); } // skip non-trade records
let (quote, trade) = decode_tcbbo_msg(&msg, instrument_id, precision, None)?; Defensive patterns
Strategy: validation
Validate before calling
// Rust
if msg.action != b'T' { return Ok(None); } Try / catch
// Rust
Err(e) => log::debug("skip: {e:#}"), Prevention
- Filter by action
- Inspect dataset actions
- Use cmbp1 decoder
- Track adapter updates
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Invalid value for `update_action`: {update_action}
- Invalid `MarketStatusAction` value: {action}
- Invalid `publisher` for record: {e}
- Invalid `{SCHEMA_PARAM}` '{schema}'. Must be one of: {allowe
- Invalid negative `contract_multiplier`: {value}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/3e9d28d5de43b77a.
Report an issue: GitHub.