nautechsystems/nautilus_trader · error

Lighter market orders support only TimeInForce::Gtc or TimeI

Error message

Lighter market orders support only TimeInForce::Gtc or TimeInForce::Ioc, was TimeInForce::{other:?}

What it means

The Lighter adapter rejects Nautilus market orders whose TimeInForce is not GTC or IOC. Lighter market orders are always immediate-or-cancel on the venue, so GTC/IOC map to ImmediateOrCancel, while any other TIF (e.g. Day, Gtd, AtTheClose) has no venue representation and is rejected at order-submission translation time with this bail! error.

Source

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

/// FOK ("fill or kill") is rejected because Lighter has no native
/// fill-or-kill primitive: routing FOK as IOC would let a partial fill
/// satisfy the request, violating the FOK guarantee.
pub(crate) fn nautilus_to_lighter_tif(
    order_type: OrderType,
    tif: TimeInForce,
    post_only: bool,
) -> anyhow::Result<LighterTimeInForce> {
    if post_only {
        return Ok(LighterTimeInForce::PostOnly);
    }

    if order_type == OrderType::Market {
        return match tif {
            TimeInForce::Gtc | 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",
            ),
            other => anyhow::bail!(
                "Lighter market orders support only TimeInForce::Gtc or TimeInForce::Ioc, was TimeInForce::{other:?}",
            ),
        };
    }

    if is_conditional_market_order(order_type) {
        return match tif {
            TimeInForce::Gtc | TimeInForce::Day | TimeInForce::Gtd => {
                Ok(LighterTimeInForce::ImmediateOrCancel)
            }
            TimeInForce::Ioc => anyhow::bail!(
                "Lighter conditional market orders require a positive expiry; Nautilus IOC cannot be represented because the venue uses IOC for post-trigger execution",
            ),
            TimeInForce::Fok => anyhow::bail!(
                "Lighter has no fill-or-kill TIF; reject FOK at the strategy or use IOC explicitly",
            ),
            other => anyhow::bail!(
                "Lighter conditional market orders do not support TimeInForce::{other:?}",

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Change the market order to TimeInForce::Gtc or TimeInForce::Ioc before submission
  2. If day/expiring behavior is required, implement a strategy-level timer to cancel unexecuted IOC orders instead of relying on venue TIF
  3. Validate orders in a strategy pre-submit hook and log/reject unsupported TIFs early

Example fix

// before
order = order_factory.market(instrument_id, side, qty, tif=TimeInForce.DAY)
// after
order = order_factory.market(instrument_id, side, qty, tif=TimeInForce.GTC)
Defensive patterns

Strategy: validation

Validate before calling

// Rust
fn is_lighter_market_tif(tif: TimeInForce) -> bool {
    matches!(tif, TimeInForce::Gtc | TimeInForce::Ioc)
}
assert!(is_lighter_market_tif(order.tif()), "Lighter market order requires GTC or IOC");

Type guard

fn is_gtc_or_ioc(tif: TimeInForce) -> bool {
    matches!(tif, TimeInForce::Gtc | TimeInForce::Ioc)
}

Prevention

When it happens

Trigger: Submitting an OrderType::Market to the Lighter adapter with TimeInForce::Day, TimeInForce::Gtd, or any TIF other than Gtc/Ioc (Fok hits its own earlier match arm). This happens in the TIF translation path in nautilus_to_lighter_tif called during CreateOrder tx construction.

Common situations: Strategy defaults or config files that set tif=DAY or GTD on all orders; templates built for equity/futures venues where Day orders are valid; porting a strategy from another adapter without reviewing per-order TIF.

Related errors


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