nautechsystems/nautilus_trader · critical
Invalid `OrderStatus`
Error message
Invalid `OrderStatus`
What it means
The `status` column string is parsed with `OrderStatus::from_str` and unwrapped with expect() during order row hydration. The panic means the stored status (expected e.g. 'INITIALIZED','SUBMITTED','FILLED',...) is not a valid OrderStatus variant, making the row undeserializable.
Source
Thrown at crates/infrastructure/src/sql/models/orders.rs:1113
let expire_time = row
.try_get::<Option<&str>, _>("expire_time")
.ok()
.and_then(|x| x.map(UnixNanos::from));
let filled_qty = row.try_get::<&str, _>("filled_qty").map(Quantity::from)?;
let liquidity_side = row
.try_get::<Option<&str>, _>("liquidity_side")
.ok()
.and_then(|x| x.map(|x| LiquiditySide::from_str(x).expect("Invalid `LiquiditySide`")));
let avg_px = row.try_get::<Option<Decimal>, _>("avg_px").ok().flatten();
let slippage = row.try_get::<Option<Decimal>, _>("slippage").ok().flatten();
let commissions = row
.try_get::<Option<Vec<String>>, _>("commissions")?
.map_or_else(Vec::new, |c| {
c.into_iter().map(|s| Money::from(&s)).collect()
});
let status = row
.try_get::<&str, _>("status")
.map(|x| OrderStatus::from_str(x).expect("Invalid `OrderStatus`"))?;
let is_post_only = row.try_get::<bool, _>("is_post_only")?;
let is_reduce_only = row.try_get::<bool, _>("is_reduce_only")?;
let is_quote_quantity = row.try_get::<bool, _>("is_quote_quantity")?;
let display_qty = row
.try_get::<Option<&str>, _>("display_qty")
.ok()
.and_then(|x| x.map(Quantity::from));
let emulation_trigger = row
.try_get::<Option<&str>, _>("emulation_trigger")
.ok()
.and_then(parse_trigger_type);
let trigger_instrument_id = row
.try_get::<Option<&str>, _>("trigger_instrument_id")
.ok()
.and_then(|x| x.map(InstrumentId::from));
let contingency_type = row
.try_get::<Option<&str>, _>("contingency_type")
.ok()View on GitHub (pinned to 18893faf8b)
Solutions
- Find bad rows: `SELECT id, status FROM orders WHERE status NOT IN (<valid list>)` and correct them
- Ensure the writer serializes OrderStatus via its canonical string conversion
- Align data with the nautilus version in use — migrate rows after upgrading the library
- Propagate a parse error instead of expect for rows from untrusted sources
Example fix
// before
OrderStatus::from_str(x).expect("Invalid `OrderStatus`")
// after
OrderStatus::from_str(x).map_err(|e| ModelError::Parse(format!("invalid status '{x}': {e}")))? Defensive patterns
Strategy: type-guard
Validate before calling
fn is_known_order_status(s: &str) -> bool {
OrderStatus::from_str(s).is_ok()
}
// use before reading: assert!(is_known_order_status(status_str)); Type guard
fn is_known_order_status(s: &str) -> bool {
OrderStatus::from_str(s).is_ok()
} Try / catch
let status = OrderStatus::from_str(x)
.map_err(|e| ModelError::Parse(format!("row {}: invalid status '{x}': {e}", row_id)))?; Prevention
- Map adapter-specific states to canonical OrderStatus before persisting
- Add a CHECK constraint on status
- Round-trip test all OrderStatus variants through the SQL model
- Run a status audit query after nautilus upgrades
When it happens
Trigger: Calling `OrderModel::from_row` where `status` holds an unknown value: adapter-only states like 'PARTIALLY_FILLED_CANCELLED', case/whitespace mismatches, or statuses written by a newer/older nautilus version.
Common situations: Schema shared across nautilus versions where the OrderStatus enum changed; external order-management systems writing their own statuses; manual data fixes.
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 `OrderType`
- Invalid `OrderSide`
- Invalid `TimeInForce`
- Invalid `LiquiditySide`
- Invalid `TriggerType`
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/acdf241deb2372c7.
Report an issue: GitHub.