nautechsystems/nautilus_trader · error

unsupported Nautilus order type for Lighter: {e}

Error message

unsupported Nautilus order type for Lighter: {e}

What it means

nautilus_to_lighter_order_type converts a Nautilus OrderType into a LighterOrderType discriminant; unsupported order types fail conversion and are wrapped in this error. Lighter only supports a subset of Nautilus order types for CreateOrder tx bodies.

Source

Thrown at crates/adapters/lighter/src/websocket/dispatch.rs:2036

    match tif {
        TimeInForce::Ioc => Ok(LighterTimeInForce::ImmediateOrCancel),
        TimeInForce::Fok => anyhow::bail!(
            "Lighter has no fill-or-kill TIF; reject FOK at the strategy or use IOC explicitly",
        ),
        TimeInForce::Gtc | TimeInForce::Day | TimeInForce::Gtd => {
            Ok(LighterTimeInForce::GoodTillTime)
        }
        other => anyhow::bail!("Lighter does not support TimeInForce::{other:?}"),
    }
}

/// Translate a Nautilus [`OrderType`] into the venue's [`LighterOrderType`]
/// discriminant for use in `CreateOrder` tx bodies.
pub(crate) fn nautilus_to_lighter_order_type(
    order_type: OrderType,
) -> anyhow::Result<LighterOrderType> {
    LighterOrderType::try_from(order_type)
        .map_err(|e| anyhow::anyhow!("unsupported Nautilus order type for Lighter: {e}"))
}

/// Compute the venue-side `order_expiry` (millis) for a Nautilus order.
///
/// - `MARKET`: `ORDER_EXPIRY_IOC` (`0`) because it has no resting trigger
///   lifetime.
/// - Conditional orders: positive expiry from `GTD` or the default GTC window.
///   Lighter uses `TimeInForce` as the post-trigger execution instruction,
///   while `OrderExpiry` controls how long the trigger can rest.
/// - `Gtd` with an explicit expire_time: the millisecond timestamp, provided
///   it is within the venue's 5-minute to 30-day lifetime range.
/// - `Ioc` / `Fok`: `ORDER_EXPIRY_IOC` (`0`): Lighter requires this exact
///   value for IOC semantics; any other value is rejected by the sequencer.
/// - `Gtc` / `Day` / `Gtd` without expiry: `now_ms + ORDER_EXPIRY_DEFAULT_GTC_MS`.
///   The venue rejects `-1` for these TIFs with `21711 invalid expiry`.
pub(crate) fn order_expiry_for(
    order_type: OrderType,
    tif: &TimeInForce,

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Use only supported order types with Lighter: LIMIT and MARKET.
  2. Emulate unsupported types client-side (e.g. manage stop triggers in the strategy and submit LIMIT/MARKET on trigger).
  3. Check the LighterOrderType::try_from(OrderType) implementation for the exact supported set before submitting.

Example fix

// before
order_factory.limit(...) // or market(...) only for Lighter
// after: unsupported
// order_factory.stop_limit(...) -> error; replace with client-side trigger + limit submit
Defensive patterns

Strategy: validation

Validate before calling

const SUPPORTED: &[OrderType] = &[OrderType::Limit, OrderType::Market];
anyhow::ensure!(SUPPORTED.contains(&order_type), "order type {order_type} unsupported on Lighter");

Prevention

When it happens

Trigger: Submitting an order whose OrderType (e.g. STOP_LIMIT, TRAILING_STOP_MARKET, or other non-Lighter types) has no TryFrom<OrderType> mapping to LighterOrderType.

Common situations: Strategy code written for venues with rich order types being ported to Lighter; defaults emitting LIMIT only sometimes and STOP variants other times; version drift adding new Nautilus order types.

Related errors


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