nautechsystems/nautilus_trader · error

Trailing offset not set

Error message

Trailing offset not set

What it means

OrderTestBuilder::get_trailing_offset unwraps Option<Decimal> set via .trailing_offset(...). build() for trailing order types (TrailingStopMarket, TrailingStopLimit) panics with 'Trailing offset not set' when absent.

Source

Thrown at crates/model/src/orders/builder.rs:246

    // ----------- LimitOffset ----------
    pub fn limit_offset(&mut self, limit_offset: Decimal) -> &mut Self {
        self.limit_offset = Some(limit_offset);
        self
    }

    fn get_limit_offset(&self) -> Decimal {
        self.limit_offset.expect("Limit offset not set")
    }

    // ----------- TrailingOffset ----------
    pub fn trailing_offset(&mut self, trailing_offset: Decimal) -> &mut Self {
        self.trailing_offset = Some(trailing_offset);
        self
    }

    fn get_trailing_offset(&self) -> Decimal {
        self.trailing_offset.expect("Trailing offset not set")
    }

    // ----------- TrailingOffsetType ----------
    pub fn trailing_offset_type(&mut self, trailing_offset_type: TrailingOffsetType) -> &mut Self {
        self.trailing_offset_type = Some(trailing_offset_type);
        self
    }

    fn get_trailing_offset_type(&self) -> TrailingOffsetType {
        self.trailing_offset_type
            .expect("Trailing offset type not set")
    }

    // ----------- TimeInForce ----------
    pub fn time_in_force(&mut self, time_in_force: TimeInForce) -> &mut Self {
        self.time_in_force = Some(time_in_force);
        self
    }

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Add .trailing_offset(Decimal::from(...)) to the builder chain before build().
  2. Pair trailing_offset with the correct trailing_offset_type (basis points vs price) so downstream validation passes.
  3. Use a fixture for trailing orders that always sets the offset.

Example fix

// before
let order = OrderTestBuilder::new(OrderType::TrailingStopMarket).instrument_id(id).quantity(qty).build();
// after
let order = OrderTestBuilder::new(OrderType::TrailingStopMarket)
    .instrument_id(id)
    .quantity(qty)
    .trailing_offset(Decimal::from(100))
    .build();
Defensive patterns

Strategy: validation

Validate before calling

if matches!(order_type, OrderType::TrailingStopMarket | OrderType::TrailingStopLimit) {
    assert!(trailing_offset.is_some(), "trailing_offset required for {:?}", order_type);
}
builder.trailing_offset(trailing_offset.unwrap()).build();

Type guard

fn order_type_needs_trailing_offset(t: OrderType) -> bool {
    matches!(t, OrderType::TrailingStopMarket | OrderType::TrailingStopLimit)
}

Try / catch

// validate before build
assert!(trailing_offset.is_some() || !order_type_needs_trailing_offset(order_type));

Prevention

When it happens

Trigger: Building a trailing stop order via OrderTestBuilder without chaining .trailing_offset(Decimal) before build().

Common situations: Creating trailing stop tests by copying a stop-order builder and missing the trailing_offset line, or data-driven tests where the offset field is empty for some rows.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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