nautechsystems/nautilus_trader · error

max_fee_per_contract must be greater than zero

Error message

max_fee_per_contract must be greater than zero

What it means

Raised by `DeriveDataClientConfig::validate` when `max_fee_per_contract` is present but is less than or equal to zero. The adapter requires a strictly positive per-contract fee cap so order requests never send a non-sensical fee bound.

Source

Thrown at crates/adapters/derive/src/config.rs:271

                .as_ref()
                .map(SecretString::expose_secret)
                .is_some_and(|s| !s.trim().is_empty())
            && self.subaccount_id.is_some()
    }

    /// Validates execution configuration invariants.
    ///
    /// # Errors
    ///
    /// Returns an error when `max_fee_per_contract` is missing or not greater
    /// than zero.
    pub fn validate(&self) -> anyhow::Result<()> {
        let Some(max_fee_per_contract) = self.max_fee_per_contract else {
            anyhow::bail!("max_fee_per_contract is required");
        };

        if max_fee_per_contract <= Decimal::ZERO {
            anyhow::bail!("max_fee_per_contract must be greater than zero");
        }
        Ok(())
    }

    /// Returns the REST API base URL, respecting environment and overrides.
    #[must_use]
    pub fn rest_url(&self) -> String {
        self.base_url_rest
            .clone()
            .unwrap_or_else(|| urls::rest_url(self.environment).to_string())
    }

    /// Returns the WebSocket URL, respecting environment and overrides.
    #[must_use]
    pub fn ws_url(&self) -> String {
        self.base_url_ws
            .clone()
            .unwrap_or_else(|| urls::ws_url(self.environment).to_string())

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Set `max_fee_per_contract` to a positive Decimal (e.g. 0.01) in the config.
  2. Verify the value parsed from the config file is positive and not 0 or negative.
  3. Validate the config early (validate()) to surface the problem before client creation.

Example fix

// before
max_fee_per_contract: Some(Decimal::ZERO),
// after
max_fee_per_contract: Some(Decimal::new(1, 2)), // 0.01
Defensive patterns

Strategy: validation

Validate before calling

if let Some(fee) = config.max_fee_per_contract {
    assert!(fee > Decimal::ZERO, "max_fee_per_contract must be > 0");
}
config.validate()?;

Try / catch

if let Err(e) = config.validate() {
    return Err(anyhow::context!(e, "fix DeriveDataClientConfig before starting"));
}

Prevention

When it happens

Trigger: Setting `max_fee_per_contract` to `0`, a negative `Decimal`, or `Decimal::ZERO` in the DeriveDataClientConfig before client construction (`new` calls `validate`).

Common situations: Using Decimal::ZERO as a placeholder/default value; parsing an unquoted numeric 0 from config; sign confusion when entering a fee value; templating configs with empty values.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


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