nautechsystems/nautilus_trader · error

max_fee_per_contract is required

Error message

max_fee_per_contract is required

What it means

Raised by `DeriveDataClientConfig::validate` when the `max_fee_per_contract` field is `None`. This configuration value is mandatory for the Derive adapter because it caps per-contract fees on order submission.

Source

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

            .as_deref()
            .is_some_and(|s| !s.trim().is_empty())
            && self
                .session_key
                .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]

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Set `max_fee_per_contract` to a positive Decimal in the Derive client config.
  2. If loading from a config file, add the missing key to the file.
  3. Call config.validate() at startup before creating the client to fail early with a clear message.

Example fix

// before
let config = DeriveDataClientConfig { env, currencies, ..Default::default() };
// after
let config = DeriveDataClientConfig {
    max_fee_per_contract: Some(Decimal::from_str("0.01")?),
    ..config
};
Defensive patterns

Strategy: validation

Validate before calling

assert!(config.max_fee_per_contract.is_some(), "set max_fee_per_contract in DeriveDataClientConfig");
config.validate()?;

Try / catch

match config.validate() {
    Ok(()) => { /* create client */ }
    Err(e) => eprintln!("Derive config invalid: {e}"),
}

Prevention

When it happens

Trigger: Constructing a DeriveDataClientConfig (or calling `new` on a client built from it) without setting `max_fee_per_contract`, e.g. building the config programmatically or deserializing a config file/TOML/JSON that omits the field.

Common situations: Copying an older config file from before the field was introduced; writing config by hand and leaving the optional field out; programmatically constructing config structs with `..Default::default()`-style partial initialization.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


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