nautechsystems/nautilus_trader · error · anyhow::Error

submit order failed

Error message

submit order failed

What it means

OKX execution client's WebSocket-path order submission: submit_regular_order spawns a task that calls place_order_with_domain_types over the WS. If the placement fails, a submit-failure event is emitted for the strategy and the task returns 'submit order failed' wrapping the underlying OKX error. Note submit_order itself returns Ok immediately since the work is spawned.

Source

Thrown at crates/adapters/okx/src/execution.rs:774

                    px_vol,
                    outcome,
                    slippage_pct,
                    rpi,
                    rpi_taker_access,
                    rpi_px_round,
                )
                .await;

            if let Err(e) = result {
                emit_submit_failure(
                    classify_okx_ws_failure(&e),
                    &emitter,
                    clock,
                    strategy_id,
                    instrument_id,
                    client_order_id,
                );
                return Err(anyhow::Error::new(e).context("submit order failed"));
            }

            Ok(())
        });

        Ok(())
    }

    fn submit_order_http(&self, cmd: &SubmitOrder) -> anyhow::Result<()> {
        let order = {
            let cache = self.core.cache();
            cache.try_order_owned(&cmd.client_order_id)?
        };
        let http_client = self.http_client.clone();
        let trade_mode = self.trade_mode_for_order(cmd.instrument_id, &cmd.params);

        let emitter = self.emitter.clone();
        let clock = self.clock;

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Subscribe to the emitted order-denied/submit-failure events; the underlying OKX error there names the rejection reason.
  2. Validate price/quantity against the instrument's tick size and lot size before submitting.
  3. Check account balance/margin and position mode (net vs long/short) matches the order side.
  4. Ensure the WS connection is healthy (heartbeats, reconnect logic) when using the WS submission path.

Example fix

// before
client.submit_order(cmd)?; // returns Ok even if WS place fails later
// after
client.submit_order(cmd)?; // also handle OrderDenied/submit-failure event for the real OKX error
Defensive patterns

Strategy: try-catch

Validate before calling

// Rust: validate against instrument rules before submit
debug_assert_eq!(qty.as_decimal() % instrument.lot_size().as_decimal(), Decimal::ZERO);
debug_assert!((price.as_decimal() % instrument.tick_size().as_decimal()).is_zero());

Try / catch

client.submit_order(&cmd)?; // Ok means spawned, not filled
// handle the async failure via actor events:
// on_event(OrderDenied { reason, .. }) => log okx rejection code and adjust order
// on_event(OrderRejected { .. }) => reconcile state

Prevention

When it happens

Trigger: submit_order routing to the WS path where the OKX place-order WS request fails — rejected order params (invalid px/sz/tif), post-only would-cross rejection, insufficient balance/margin, rate limit, or WS dropped mid-request.

Common situations: Trading instruments with wrong tick/lot sizes, submitting during OKX WS disconnects, insufficient funds, or FOK orders that cannot fill; failures surface asynchronously in the spawned task, not from submit_order's return.

Related errors


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