nautechsystems/nautilus_trader · error

Order denied: invalid status for {}, expected INITIALIZED

Error message

Order denied: invalid status for {}, expected INITIALIZED

What it means

submit_order_native only accepts orders whose status is INITIALIZED. If an order with any other lifecycle status (e.g. SUBMITTED, DENIED, FILLED) is passed again, the submission is denied with this error to prevent duplicate or stale submissions. Orders are meant to flow through this path exactly once.

Source

Thrown at crates/trading/src/strategy/mod.rs:2335

pub(super) fn submit_order_native<T>(
    strategy: &mut T,
    order: &OrderAny,
    position_id: Option<PositionId>,
    client_id: Option<ClientId>,
    params: Option<Params>,
) -> anyhow::Result<()>
where
    T: Strategy + StrategyNative + ?Sized,
{
    let core = StrategyNative::strategy_core_mut(strategy);

    let trader_id = registered_trader_id(core)?;
    let strategy_id = registered_strategy_id(core)?;
    let ts_init = core.clock_mut().timestamp_ns();

    if order.status() != OrderStatus::Initialized {
        anyhow::bail!(
            "Order denied: invalid status for {}, expected INITIALIZED",
            order.client_order_id()
        );
    }

    let market_exit_tag = core.market_exit_tag;
    let is_market_exit_order = order
        .tags()
        .is_some_and(|tags| tags.contains(&market_exit_tag));
    let should_deny_for_market_exit =
        core.is_exiting && !order.is_reduce_only() && !is_market_exit_order;

    if should_deny_for_market_exit {
        strategy.deny_order(order, Ustr::from("MARKET_EXIT_IN_PROGRESS"));
        return Ok(());
    }

    let core = StrategyNative::strategy_core_mut(strategy);

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Only call submit_order_native once per order, immediately after construction while status is INITIALIZED
  2. Check order.status() before submitting and create a new order for retries
  3. Trace why the order's status already changed (e.g. an earlier submit, deny, or event application)

Example fix

// before
strategy.submit_order_native(&order)?;
// after
if order.status() == OrderStatus::Initialized {
    strategy.submit_order_native(&order)?;
} else {
    // create a new order for resubmission
}
Defensive patterns

Strategy: validation

Validate before calling

// Rust
if order.status() != OrderStatus::Initialized {
    // create a new order instead of resubmitting
}

Try / catch

// Rust
match res {
    Err(e) if e.to_string().contains("expected INITIALIZED") => {
        log::warn!("order already submitted; build a new order for retry");
    }
    other => other?,
}

Prevention

When it happens

Trigger: Calling submit_order_native (via binding_submit_order) with an order object that was already submitted, denied, or otherwise transitioned away from OrderStatus::Initialized.

Common situations: Retrying a submission after a failure without creating a fresh order; submitting the same order instance from multiple code paths; reusing a cached order after a strategy restart.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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