nautechsystems/nautilus_trader · error

Invalid `BookAction`, was '{invalid}'

Error message

Invalid `BookAction`, was '{invalid}'

What it means

`parse_book_action` converts the Databento MBO action character ('A' add, 'C' cancel, 'M' modify, 'R' clear) into a `BookAction` enum. Fill ('F') and None ('N') are deliberately excluded because their book impact arrives as explicit Cancel/Modify events; any other character is invalid and bails.

Source

Thrown at crates/adapters/databento/src/decode/primitives.rs:72

    }
}

/// Parses a Databento book action character into a `BookAction` enum.
///
/// # Errors
///
/// Returns an error if `c` is not a valid `BookAction` character.
pub fn parse_book_action(c: c_char) -> anyhow::Result<BookAction> {
    match c as u8 as char {
        'A' => Ok(BookAction::Add),
        'C' => Ok(BookAction::Delete),
        'M' => Ok(BookAction::Update),
        'R' => Ok(BookAction::Clear),
        // 'F' (Fill) and 'N' (None) are deliberately NOT book actions: fills
        // are attribution records whose book impact arrives as the explicit
        // Cancel/Modify of the same match event (`decode_mbo_msg` filters
        // them out before calling this).
        invalid => anyhow::bail!("Invalid `BookAction`, was '{invalid}'"),
    }
}

/// Parses a Databento option kind character into an `OptionKind` enum.
///
/// # Errors
///
/// Returns an error if `c` is not a valid `OptionKind` character.
pub fn parse_option_kind(c: c_char) -> anyhow::Result<OptionKind> {
    match c as u8 as char {
        'C' => Ok(OptionKind::Call),
        'P' => Ok(OptionKind::Put),
        invalid => anyhow::bail!("Invalid `OptionKind`, was '{invalid}'"),
    }
}

pub(super) fn parse_currency_or_usd_default(
    value: Result<&str, impl std::error::Error>,

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Verify the record's action field against the Databento MBO spec
  2. Ensure 'F'/'N' records are filtered before parse (decode_mbo_msg does this) — upgrade if your version doesn't
  3. Upgrade the adapter/dbn crates if Databento introduced new action codes
  4. Sanitize or drop corrupt records at the stream source

Example fix

// before
MboMsg { action: b'X', ... } // invalid action char
// after
MboMsg { action: b'A', ... } // A/C/M/R only
Defensive patterns

Strategy: validation

Validate before calling

fn is_valid_book_action(action: u8) -> bool { matches!(action, b'A' | b'C' | b'M' | b'R') }
// filter 'F' and 'N' before decode, as decode_mbo_msg does

Type guard

fn is_book_action(action: u8) -> Option<u8> { matches!(action, b'A'|b'C'|b'M'|b'R').then_some(action) }

Try / catch

match decode_record(record) {
    Ok(d) => d,
    Err(e) if e.to_string().contains("Invalid `BookAction`") => { /* drop corrupt record */ }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Decoding an `MboMsg` whose `action` field is a character outside {'A','C','M','R'} (and the deliberately-unsupported 'F'/'N' which decode_mbo_msg should filter out first).

Common situations: Corrupt or truncated records; new Databento action codes added upstream; feeding hand-crafted MBO records in tests or replay with a wrong action char.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/47d25d6ef9d502b6. Report an issue: GitHub.