nautechsystems/nautilus_trader · error
Invalid `OrderSide`
Error message
Invalid `OrderSide`
What it means
`AccountPosition::from_row` in positions.rs parses the `entry` column as an `OrderSide` via `OrderSide::from_str` and unwraps it with `.expect("Invalid `OrderSide`")`. If the stored string is not a valid `OrderSide` ('BUY'/'SELL'), the parse returns `None` and row deserialization panics. The library assumes positions rows were written only through its own serialization.
Source
Thrown at crates/infrastructure/src/sql/models/positions.rs:53
let trader_id = row.try_get::<&str, _>("trader_id").map(TraderId::from)?;
let strategy_id = row
.try_get::<&str, _>("strategy_id")
.map(StrategyId::from)?;
let instrument_id = row
.try_get::<&str, _>("instrument_id")
.map(InstrumentId::from)?;
let account_id = row.try_get::<&str, _>("account_id").map(AccountId::from)?;
let opening_order_id = row
.try_get::<&str, _>("opening_order_id")
.map(ClientOrderId::from)?;
let closing_order_id = row
.try_get::<Option<&str>, _>("closing_order_id")
.ok()
.and_then(|x| x.map(ClientOrderId::from));
let entry = row
.try_get::<&str, _>("entry")
.map(OrderSide::from_str)?
.expect("Invalid `OrderSide`");
let side = row
.try_get::<&str, _>("side")
.map(PositionSide::from_str)?
.expect("Invalid `PositionSide`");
let signed_qty = row.try_get::<f64, _>("signed_qty")?;
let quantity = row.try_get::<&str, _>("quantity").map(Quantity::from)?;
let peak_qty = row.try_get::<&str, _>("peak_qty").map(Quantity::from)?;
let quote_currency = row
.try_get::<&str, _>("quote_currency")
.map(Currency::from)?;
let base_currency = row
.try_get::<Option<&str>, _>("base_currency")
.ok()
.and_then(|x| x.map(Currency::from));
let settlement_currency = row
.try_get::<&str, _>("settlement_currency")
.map(Currency::from)?;
let avg_px_open = row.try_get::<f64, _>("avg_px_open")?;View on GitHub (pinned to 18893faf8b)
Solutions
- Check the failing row's `entry` value in Postgres and rewrite it as a valid `OrderSide` ('BUY' or 'SELL')
- Audit all writers of the positions table to ensure they serialize `OrderSide` via the library's `to_string`
- Run `SELECT DISTINCT entry FROM positions` and validate every distinct value against `OrderSide::from_str`
- Rebuild corrupt rows from the underlying order/fill events rather than ad-hoc string edits
Example fix
// before entry = 'buy' // after entry = 'BUY'
Defensive patterns
Strategy: validation
Validate before calling
fn valid_order_side(s: &str) -> bool { OrderSide::from_str(s).is_some() }
// check before persisting or accepting positions rows Type guard
fn parse_order_side(s: &str) -> Option<OrderSide> { OrderSide::from_str(s) } Prevention
- Serialize `OrderSide` with the library `to_string`, never hand-built strings
- Run `SELECT DISTINCT entry FROM positions` checks after migrations/imports
- Keep the positions table writer and reader on the same schema version
When it happens
Trigger: Reading a `positions` row whose `entry` column is not exactly a valid `OrderSide` string (e.g. empty, 'buy' in unexpected casing, 'LONG', or numeric exchange side codes like '1'/'B'), typically from manual inserts or a version/schema mismatch.
Common situations: Manual DB edits or ETL scripts writing position rows; restoring rows from a different nautilus schema version; adapters persisting raw venue side strings instead of the nautilus enum text; typos in seed data.
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
- Invalid `ContingencyType`
- Invalid `PositionSide`
- Execution intent {} has unknown purpose {}
- Invalid scientific notation exponent '{exponent}': must be a
- Invalid NodeState value
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/d33a476a85af7968.
Report an issue: GitHub.