{"record":{"id":"d17efd18faf96456","repo":"nautechsystems/nautilus_trader","slug":"max-fee-per-contract-is-required","errorCode":null,"errorMessage":"max_fee_per_contract is required","messagePattern":"max_fee_per_contract is required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/derive/src/config.rs","lineNumber":267,"sourceCode":"            .as_deref()\n            .is_some_and(|s| !s.trim().is_empty())\n            && self\n                .session_key\n                .as_ref()\n                .map(SecretString::expose_secret)\n                .is_some_and(|s| !s.trim().is_empty())\n            && self.subaccount_id.is_some()\n    }\n\n    /// Validates execution configuration invariants.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error when `max_fee_per_contract` is missing or not greater\n    /// than zero.\n    pub fn validate(&self) -> anyhow::Result<()> {\n        let Some(max_fee_per_contract) = self.max_fee_per_contract else {\n            anyhow::bail!(\"max_fee_per_contract is required\");\n        };\n\n        if max_fee_per_contract <= Decimal::ZERO {\n            anyhow::bail!(\"max_fee_per_contract must be greater than zero\");\n        }\n        Ok(())\n    }\n\n    /// Returns the REST API base URL, respecting environment and overrides.\n    #[must_use]\n    pub fn rest_url(&self) -> String {\n        self.base_url_rest\n            .clone()\n            .unwrap_or_else(|| urls::rest_url(self.environment).to_string())\n    }\n\n    /// Returns the WebSocket URL, respecting environment and overrides.\n    #[must_use]","sourceCodeStart":249,"sourceCodeEnd":285,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/derive/src/config.rs#L249-L285","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Set `max_fee_per_contract` to a positive Decimal in the Derive client config.","If loading from a config file, add the missing key to the file.","Call config.validate() at startup before creating the client to fail early with a clear message."],"exampleFix":"// before\nlet config = DeriveDataClientConfig { env, currencies, ..Default::default() };\n// after\nlet config = DeriveDataClientConfig {\n    max_fee_per_contract: Some(Decimal::from_str(\"0.01\")?),\n    ..config\n};","handlingStrategy":"validation","validationCode":"assert!(config.max_fee_per_contract.is_some(), \"set max_fee_per_contract in DeriveDataClientConfig\");\nconfig.validate()?;","typeGuard":null,"tryCatchPattern":"match config.validate() {\n    Ok(()) => { /* create client */ }\n    Err(e) => eprintln!(\"Derive config invalid: {e}\"),\n}","preventionTips":["Always set max_fee_per_contract when building DeriveDataClientConfig.","Call validate() immediately after config load/deserialization.","Keep config templates updated with all required fields."],"tags":["configuration","missing-field","derive","validation"],"backgroundTag":"missing-required-config-field","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}