nautechsystems/nautilus_trader · warning

Lighter `{kind:?}` has no Nautilus order-type equivalent

Error message

Lighter `{kind:?}` has no Nautilus order-type equivalent

What it means

nautilus_order_type maps Lighter's order-kind enum onto NautilusTrader's OrderType. Most kinds have direct equivalents, but TWAP, TWAP-sub-orders, and Liquidation orders have no Nautilus order-type representation, so the mapping intentionally returns an error rather than guessing a lossy type.

Source

Thrown at crates/adapters/lighter/src/websocket/parse.rs:1230

}

fn nautilus_order_side(side: LighterOrderSide) -> OrderSide {
    match side {
        LighterOrderSide::Buy => OrderSide::Buy,
        LighterOrderSide::Sell => OrderSide::Sell,
    }
}

fn nautilus_order_type(kind: LighterOrderKind) -> anyhow::Result<OrderType> {
    match kind {
        LighterOrderKind::Limit => Ok(OrderType::Limit),
        LighterOrderKind::Market => Ok(OrderType::Market),
        LighterOrderKind::StopLoss => Ok(OrderType::StopMarket),
        LighterOrderKind::StopLossLimit => Ok(OrderType::StopLimit),
        LighterOrderKind::TakeProfit => Ok(OrderType::MarketIfTouched),
        LighterOrderKind::TakeProfitLimit => Ok(OrderType::LimitIfTouched),
        LighterOrderKind::Twap | LighterOrderKind::TwapSub | LighterOrderKind::Liquidation => Err(
            anyhow::anyhow!("Lighter `{kind:?}` has no Nautilus order-type equivalent",),
        ),
    }
}

fn nautilus_time_in_force(
    tif: LighterOrderTimeInForce,
    order_expiry: i64,
) -> (TimeInForce, Option<UnixNanos>) {
    match tif {
        LighterOrderTimeInForce::ImmediateOrCancel => (TimeInForce::Ioc, None),
        LighterOrderTimeInForce::PostOnly | LighterOrderTimeInForce::GoodTillTime => {
            // Lighter uses positive expiry for GTD and nonpositive expiry for GTC;
            // PostOnly uses the same expiry field plus an independent report flag.
            if order_expiry > 0 {
                match parse_millis_to_nanos(order_expiry as u64) {
                    Ok(expiry) => (TimeInForce::Gtd, Some(expiry)),
                    Err(_) => (TimeInForce::Gtc, None),
                }

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Skip (with a warning log) order-status reports whose order type cannot be mapped, instead of failing the whole websocket message batch, if you only need the mappable orders.
  2. Avoid placing TWAP/algorithmic orders through Lighter's native algo endpoints when using this adapter; place plain limit/market/stop orders it can represent.
  3. Track liquidation events separately (account balance/position updates) rather than relying on the order-status stream, since Liquidation orders are exchange-initiated.
  4. If you must consume these reports, file/extend support by adding explicit mappings or an OrderType passthrough for these kinds.
Defensive patterns

Strategy: try-catch

Validate before calling

fn is_mappable(kind: &LighterOrderKind) -> bool {
    !matches!(kind, LighterOrderKind::Twap | LighterOrderKind::TwapSub | LighterOrderKind::Liquidation)
}

Try / catch

match nautilus_order_type(kind) {
    Ok(t) => use_type(t),
    Err(e) => log::warn!("ignoring unmappable Lighter order kind: {e}"),
}

Prevention

When it happens

Trigger: parse_ws_order_status_report processes an order-status update for an order whose kind is LighterOrderKind::Twap, TwapSub, or Liquidation — typically an exchange-initiated liquidation or an algorithmic TWAP order placed outside this adapter.

Common situations: Your account gets liquidated (or partially liquidated by the exchange) and the resulting order update cannot be translated; a TWAP algo order is placed directly on the Lighter UI/API and then appears in the adapter's order stream; backtesting/reconciliation pulls history containing unsupported order kinds.

Related errors


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