nautechsystems/nautilus_trader · error · anyhow::Error

unrecognized side '{side}'

Error message

unrecognized side '{side}'

What it means

The Python loader load_binance_order_book_deltas(file_path, nrows) expects Binance order book delta CSVs with columns symbol,timestamp,last_update_id,side,update_type,price,qty, where side must be 'b' or 'a' (compared case-insensitively). Any other value in the side column ('buy', 'sell', '', 'bid', garbage from shifted columns) raises this error while mapping rows.

Source

Thrown at crates/adapters/binance/src/python/data.rs:93

    let mut reader = csv::Reader::from_path(file_path).with_context(|| {
        format!(
            "failed to open Binance order book CSV {}",
            file_path.display(),
        )
    })?;

    reader
        .deserialize::<BinanceOrderBookDeltaCsvRow>()
        .take(nrows.unwrap_or(usize::MAX))
        .map(|row| map_row(&row?))
        .collect()
}

fn map_row(row: &BinanceOrderBookDeltaCsvRow) -> anyhow::Result<BinanceOrderBookDeltaRow> {
    let side = match row.side.to_ascii_lowercase().as_str() {
        "b" => "BUY",
        "a" => "SELL",
        side => anyhow::bail!("unrecognized side '{side}'"),
    };
    let is_snapshot = row.update_type == "snap";
    let action = if is_snapshot {
        "ADD"
    } else if row.qty == 0.0 {
        "DELETE"
    } else {
        "UPDATE"
    };

    Ok(BinanceOrderBookDeltaRow {
        timestamp: row.timestamp,
        instrument_id: format!("{}.BINANCE", row.symbol),
        action,
        side,
        price: row.price,
        size: row.qty,
        order_id: 0,

View on GitHub (pinned to a4b06ed870)

Solutions

  1. Re-export or transform the file so side contains only 'b' or 'a' (any case)
  2. Preprocess the CSV: map buy->b, sell->a and reject empty values before loading
  3. Verify the header and column order match the expected schema (symbol,timestamp,last_update_id,side,update_type,price,qty) and that update_type uses 'snap' for snapshots

Example fix

# before
df.to_csv("deltas.csv")  # side column holds 'buy' / 'sell'

# after
side_map = {"buy": "b", "sell": "a", "b": "b", "a": "a"}
df["side"] = df["side"].str.strip().str.lower().map(side_map)
assert df["side"].isin(["b", "a"]).all(), "unmapped side values remain"
df.to_csv("deltas.csv")
Defensive patterns

Strategy: validation

Validate before calling

import pandas as pd

df = pd.read_csv(path)
allowed = {"b", "a"}
normalized = df["side"].str.strip().str.lower()
assert normalized.isin(allowed).all(), (
    f"CSV has non-Binance side values: {set(normalized) - allowed}"
)

Type guard

def is_binance_side(value: str) -> bool:
    return value.strip().lower() in {"b", "a"}

Prevention

When it happens

Trigger: Calling nautilus_trader.adapters.binance load_binance_order_book_deltas on a CSV whose side column is not Binance's single-letter b/a format, e.g. an export from another exchange or a hand-written file using 'buy'/'sell'.

Common situations: Reusing data pipelines built for generic book CSVs; schema drift after re-export; files with extra or reordered columns putting wrong data into the side field.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@a4b06ed870 (2026-08-16). Data as JSON: /api/errors/7c462e0c56f4d7e0. Report an issue: GitHub.