{"record":{"id":"af3616f15de409df","repo":"nautechsystems/nautilus_trader","slug":"max-fee-per-contract-must-be-greater-than-zero","errorCode":null,"errorMessage":"max_fee_per_contract must be greater than zero","messagePattern":"max_fee_per_contract must be greater than zero","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/derive/src/config.rs","lineNumber":271,"sourceCode":"                .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]\n    pub fn ws_url(&self) -> String {\n        self.base_url_ws\n            .clone()\n            .unwrap_or_else(|| urls::ws_url(self.environment).to_string())","sourceCodeStart":253,"sourceCodeEnd":289,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/derive/src/config.rs#L253-L289","documentation":"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.","triggerScenarios":"Setting `max_fee_per_contract` to `0`, a negative `Decimal`, or `Decimal::ZERO` in the DeriveDataClientConfig before client construction (`new` calls `validate`).","commonSituations":"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.","solutions":["Set `max_fee_per_contract` to a positive Decimal (e.g. 0.01) in the config.","Verify the value parsed from the config file is positive and not 0 or negative.","Validate the config early (validate()) to surface the problem before client creation."],"exampleFix":"// before\nmax_fee_per_contract: Some(Decimal::ZERO),\n// after\nmax_fee_per_contract: Some(Decimal::new(1, 2)), // 0.01","handlingStrategy":"validation","validationCode":"if let Some(fee) = config.max_fee_per_contract {\n    assert!(fee > Decimal::ZERO, \"max_fee_per_contract must be > 0\");\n}\nconfig.validate()?;","typeGuard":null,"tryCatchPattern":"if let Err(e) = config.validate() {\n    return Err(anyhow::context!(e, \"fix DeriveDataClientConfig before starting\"));\n}","preventionTips":["Never use Decimal::ZERO as a placeholder for fee caps.","Clamp parsed config values to a positive minimum.","Run validate() at startup, not at first order."],"tags":["configuration","validation","value-out-of-range","derive"],"backgroundTag":"invalid-config-value","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"}