{"record":{"id":"9729b2dfa55ca254","repo":"nautechsystems/nautilus_trader","slug":"default-leverage-requires-spot-account-type-margin","errorCode":null,"errorMessage":"default_leverage requires spot_account_type=Margin","messagePattern":"default_leverage requires spot_account_type=Margin","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/kraken/src/config.rs","lineNumber":299,"sourceCode":"\n    /// Returns the WebSocket URL for the configured product type and environment.\n    pub fn ws_url(&self) -> String {\n        self.ws_url.clone().unwrap_or_else(|| {\n            get_kraken_ws_private_url(self.product_type, self.environment).to_string()\n        })\n    }\n\n    /// Validates config invariants.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if `default_leverage` is set on a Cash account or the demo environment is\n    /// used for Spot.\n    pub fn validate(&self) -> anyhow::Result<()> {\n        validate_product_environment(self.product_type, self.environment)?;\n\n        if self.default_leverage.is_some() && self.spot_account_type == AccountType::Cash {\n            anyhow::bail!(\"default_leverage requires spot_account_type=Margin\");\n        }\n        Ok(())\n    }\n}\n\nfn validate_product_environment(\n    product_type: KrakenProductType,\n    environment: KrakenEnvironment,\n) -> anyhow::Result<()> {\n    if product_type == KrakenProductType::Spot && environment == KrakenEnvironment::Demo {\n        anyhow::bail!(\"Kraken Spot does not support the demo environment\");\n    }\n    Ok(())\n}\n\n#[cfg(test)]\nmod tests {\n    use rstest::rstest;","sourceCodeStart":281,"sourceCodeEnd":317,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/kraken/src/config.rs#L281-L317","documentation":"Kraken Spot client config validation enforces that `default_leverage` is only valid on a Margin (not Cash) Spot account. Leverage on a Cash account is meaningless and would be rejected or ignored downstream, so `validate()` fails early with this error.","triggerScenarios":"Building a Kraken adapter config with `default_leverage = Some(x)` while `spot_account_type` is `AccountType::Cash`, then calling `validate()` during client construction/connect.","commonSituations":"Copy-pasting a config template with leverage set while running a cash Spot account; switching spot_account_type to Cash without removing default_leverage.","solutions":["Remove `default_leverage` from the config, or","Set `spot_account_type = AccountType::Margin` if the account really is a margin account","Re-run validate() after the change"],"exampleFix":"// before\nlet config = KrakenDataClientConfig {\n    spot_account_type: AccountType::Cash,\n    default_leverage: Some(Decimal::from(5)),\n    ..Default::default()\n};\n// after\nlet config = KrakenDataClientConfig {\n    spot_account_type: AccountType::Margin,\n    default_leverage: Some(Decimal::from(5)),\n    ..Default::default()\n};","handlingStrategy":"validation","validationCode":"if cfg.default_leverage.is_some() && cfg.spot_account_type == AccountType::Cash {\n    panic!(\"default_leverage cannot be set with a Cash spot account\");\n}\ncfg.validate().expect(\"invalid Kraken config\");","typeGuard":null,"tryCatchPattern":"match config.validate() {\n    Ok(()) => { /* build client */ }\n    Err(e) if e.to_string().contains(\"default_leverage\") => {\n        config.default_leverage = None;\n        /* retry */\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Always call validate() on Kraken configs at startup before connecting","Keep leverage settings only in margin-account config profiles","Derive configs from account type, not from shared templates"],"tags":["rust","kraken-spot","config-validation","leverage"],"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-14T05:17:10.506Z"}