nautechsystems/nautilus_trader · error

Failed to build order params: {e}

Error message

Failed to build order params: {e}

What it means

The spot order submission converts a Nautilus order request into Kraken `PlaceOrderParams` via a builder. When `build()` fails its validation checks (invalid combination of side, type, prices, quantities, TIF, etc.), the adapter wraps the error in this message. No HTTP request is sent; the problem is purely in the constructed parameters.

Source

Thrown at crates/adapters/kraken/src/http/spot/client.rs:3181

            if !valid_tiers.contains(&(n as i32)) {
                anyhow::bail!(
                    "Leverage {n}:1 not supported for {raw_symbol} on {side_label} side (valid: {valid_tiers:?})"
                );
            }
            builder.leverage(format!("{n}:1"));
        }

        if reduce_only {
            if account_type != AccountType::Margin {
                anyhow::bail!("reduce_only requires spot_account_type=Margin (current: Cash)");
            }
            builder.reduce_only(true);
        }

        builder
            .build()
            .map_err(|e| anyhow::anyhow!("Failed to build order params: {e}"))
    }
}

fn collect_spot_statuses(
    asset_pairs: &AssetPairsResponse,
) -> AHashMap<InstrumentId, MarketStatusAction> {
    asset_pairs
        .iter()
        .map(|(_, definition)| {
            let symbol_str = definition.wsname.as_ref().unwrap_or(&definition.altname);
            let normalized_symbol = normalize_spot_symbol(symbol_str.as_str());
            let instrument_id = InstrumentId::new(Symbol::new(&normalized_symbol), *KRAKEN_VENUE);
            let action = definition
                .status
                .map_or(MarketStatusAction::Trading, MarketStatusAction::from);

            (instrument_id, action)
        })

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Read the inner `{e}` message to identify the failed builder validation.
  2. Ensure required fields per order type are set (price for limit orders, stop/trigger price for conditional orders).
  3. Validate quantity and prices are positive and correctly formatted (use Price/Quantity `to_string()`).
  4. Check TIF and flags (post_only, reduce_only, leverage) form a combination Kraken spot accepts.

Example fix

// before
builder.order_type("limit"); // no price set -> build() fails
// after
builder.order_type("limit").price(order.price().unwrap().to_string());
Defensive patterns

Strategy: validation

Validate before calling

fn validate_order(req: &OrderRequest) -> Result<(), String> {
    if req.quantity <= Decimal::ZERO { return Err("quantity must be positive".into()); }
    if req.order_type == "limit" && req.price.map_or(true, |p| p <= Decimal::ZERO) {
        return Err("limit order requires a positive price".into());
    }
    Ok(())
}

Try / catch

match client.submit_order(req).await {
    Ok(resp) => resp,
    Err(e) if e.to_string().contains("Failed to build order params") => {
        log::error!("malformed order request {:?}: {e}", req);
        return Err(e); // do not retry; fix the request
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Placing a spot order with parameters the builder rejects: missing price on a limit order, invalid order-type/field combinations, non-positive quantity or price, leverage/trigger fields invalid per the builder's rules.

Common situations: Strategy emits a limit order with a None/unset price; zero or negative quantity from position math; post-only/reduce-only flags combined in ways Kraken's param schema disallows; precision-lost price strings.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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