{"record":{"id":"e2bb4f688a014ea9","repo":"nautechsystems/nautilus_trader","slug":"unknown-trade-direction","errorCode":null,"errorMessage":"Unknown trade direction: {}","messagePattern":"Unknown trade direction: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/deribit/src/websocket/parse.rs","lineNumber":892,"sourceCode":"            \"MT\" => \"both\",\n            _ => liq,\n        };\n        log::warn!(\n            \"Liquidation trade: {} trade_id={} order_id={} liquidation_side={} direction={} amount={} price={}\",\n            instrument_id,\n            msg.trade_id,\n            msg.order_id,\n            who,\n            msg.direction,\n            msg.amount,\n            msg.price,\n        );\n    }\n\n    let order_side = match msg.direction.as_str() {\n        \"buy\" => OrderSide::Buy,\n        \"sell\" => OrderSide::Sell,\n        _ => anyhow::bail!(\"Unknown trade direction: {}\", msg.direction),\n    };\n\n    let price_precision = instrument.price_precision();\n    let size_precision = instrument.size_precision();\n\n    let last_qty = Quantity::from_decimal_dp(msg.amount, size_precision)?;\n    let last_px = Price::from_decimal_dp(msg.price, price_precision)?;\n\n    let liquidity_side = match msg.liquidity.as_str() {\n        \"M\" => LiquiditySide::Maker,\n        \"T\" => LiquiditySide::Taker,\n        _ => LiquiditySide::NoLiquiditySide,\n    };\n\n    // Get fee currency from the fee_currency field\n    let fee_currency = Currency::from(&msg.fee_currency);\n    let commission = Money::from_decimal(msg.fee, fee_currency)?;\n","sourceCodeStart":874,"sourceCodeEnd":910,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/deribit/src/websocket/parse.rs#L874-L910","documentation":"Deribit user-trade websocket messages include a `direction` field that must be \"buy\" or \"sell\". `parse_user_trade_msg` maps this to Nautilus `OrderSide`. Any other string means the trade cannot be converted into a FillReport, so the parser bails with this error.","triggerScenarios":"`parse_user_trade_msg` invoked via `route_user_trades` or `request_fill_reports` with a trade message whose `direction` is not exactly \"buy\" or \"sell\" (wrong casing, empty string, unmapped field, or new Deribit value).","commonSituations":"Deribit adding a new direction value or changing the schema; users replaying recorded/synthetic trade payloads with malformed direction; JSON deserialization bugs mapping the wrong source field into `direction`.","solutions":["Inspect the raw websocket payload to see the actual `direction` value","Normalize the value (trim/lowercase) before parsing","Update the adapter if Deribit changed or extended the direction vocabulary"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"fn is_valid_direction(d: &str) -> bool { matches!(d, \"buy\" | \"sell\") }","typeGuard":"fn is_valid_trade_direction(d: &str) -> bool { matches!(d, \"buy\" | \"sell\") }","tryCatchPattern":"match parse_user_trade_msg(&msg, &instrument) {\n    Ok(fill) => { /* use fill */ }\n    Err(e) => tracing::error!(trade_id = %msg.trade_id, %e, \"dropping unparseable trade message\"),\n}","preventionTips":["Normalize direction casing before parsing","Validate synthetic/replayed payloads against the current Deribit schema","Watch adapter changelogs for Deribit message schema updates"],"tags":["rust","deribit","websocket","parsing","trades"],"backgroundTag":"invalid-enum-value","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}