nautechsystems/nautilus_trader · error

Invalid zero size for {action}

Error message

Invalid zero size for {action}

What it means

When parsing a Tardis order book level, only a Delete action may carry a zero size. Any other action (Add/Update) with size == 0 is considered corrupt input, so parse_book_level rejects it via anyhow::ensure! before constructing the OrderBookDelta.

Source

Thrown at crates/adapters/tardis/src/machine/parse.rs:493

    level: &BookLevel,
    is_snapshot: bool,
    ts_event: UnixNanos,
    ts_init: UnixNanos,
) -> anyhow::Result<OrderBookDelta> {
    let amount = normalize_amount(level.amount, size_precision);
    let action = parse_book_action(is_snapshot, amount);
    let price = Price::new(level.price, price_precision);
    let size = Quantity::new(amount, size_precision);
    let order_id = 0; // Not applicable for L2 data
    let order = BookOrder::new(side, price, size, order_id);
    let flags = if is_snapshot {
        RecordFlag::F_SNAPSHOT as u8
    } else {
        0
    };
    let sequence = 0; // Not available

    anyhow::ensure!(
        !(action != BookAction::Delete && size.is_zero()),
        "Invalid zero size for {action}"
    );

    Ok(OrderBookDelta::new(
        instrument_id,
        action,
        order,
        flags,
        sequence,
        ts_event,
        ts_init,
    ))
}

/// Parse a book snapshot message into a quote tick, returning an error on invalid data.
/// Parse a book snapshot message into a quote tick.
///

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Pre-filter Tardis book records where action != 'delete' and size == 0 before feeding the machine parser.
  2. Treat such records as deletes if that matches the venue semantics (set action to delete instead of add/update).
  3. Re-download the affected Tardis data range; the record may be corrupt in the source capture.
  4. If legitimate for a venue, update the adapter's normalization (map zero-size non-delete to Delete) upstream of this check.

Example fix

// before
anyhow::ensure!(!(action != BookAction::Delete && size.is_zero()), "Invalid zero size for {action}");
// after
let action = if action != BookAction::Delete && size.is_zero() {
    tracing::debug!("Coercing zero-size {action} to Delete");
    BookAction::Delete
} else {
    action
};
Defensive patterns

Strategy: validation

Validate before calling

// filter Tardis book levels before parsing
levels.retain(|lvl| lvl.action == "delete" || lvl.size > 0);

Type guard

fn is_valid_level(lvl: &BookLevel) -> bool { lvl.action == BookAction::Delete || !lvl.size.is_zero() }

Prevention

When it happens

Trigger: parse_book_msg_as_deltas -> parse_book_level receiving a Tardis book record with action != 'delete' and size == 0 (or PriceSize parsed from a record whose size field is 0/null).

Common situations: Corrupt or non-conformant Tardis data files; venue-specific anomalies in recorded L2/L3 streams; a Tardis schema change emitting zero-size updates for non-delete actions.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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