{"record":{"id":"be92608cae8d60df","repo":"nautechsystems/nautilus_trader","slug":"failed-to-repay-spot-borrow-for-coin-e","errorCode":null,"errorMessage":"Failed to repay spot borrow for {coin}: {e}","messagePattern":"Failed to repay spot borrow for (.+?): (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/bybit/src/http/client.rs","lineNumber":2366,"sourceCode":"    ///\n    /// # Errors\n    ///\n    /// Returns an error if:\n    /// - Credentials are missing.\n    /// - The request fails.\n    /// - Called during the hourly interest-calculation window (mm:04:00-mm:05:30 UTC each hour).\n    /// - Insufficient spot balance for repayment.\n    pub async fn repay_spot_borrow(\n        &self,\n        coin: &str,\n        amount: Option<Quantity>,\n    ) -> anyhow::Result<BybitNoConvertRepayResponse> {\n        let amount_str = amount.as_ref().map(|q| q.to_string());\n        let response = self\n            .inner\n            .no_convert_repay(coin, amount_str.as_deref())\n            .await\n            .map_err(|e| anyhow::anyhow!(\"Failed to repay spot borrow for {coin}: {e}\"))?;\n        Self::ensure_repay_accepted(coin, response.result.result_status)?;\n        Ok(response)\n    }\n\n    /// Repays spot borrows for a specific coin, converting other assets if required.\n    ///\n    /// Unlike [`Self::repay_spot_borrow`], this uses the venue's manual repay endpoint,\n    /// which may draw on other holdings when the debt coin's spot balance is insufficient.\n    ///\n    /// # Parameters\n    ///\n    /// - `coin`: The coin to repay (e.g., \"BTC\", \"ETH\")\n    /// - `amount`: Optional amount to repay. If None, repays all outstanding borrows.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if:\n    /// - Credentials are missing.","sourceCodeStart":2348,"sourceCodeEnd":2384,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/bybit/src/http/client.rs#L2348-L2384","documentation":"The no-convert spot repay wrapper calls the inner no_convert_repay endpoint and maps any request error into an anyhow error naming the coin. After the request succeeds, ensure_repay_accepted additionally validates the result status. This error is the map_err wrapper, so {e} holds the underlying cause (HTTP failure, Bybit rejection like insufficient balance, auth error).","triggerScenarios":"Calling repay_spot_borrow_no_convert when the HTTP request fails, the API key lacks permissions, the amount exceeds the outstanding borrow, or Bybit rejects the repay order for that coin.","commonSituations":"End-of-position cleanup code repaying spot borrows; repaying more than the current liability; Bybit maintenance windows or 5xx errors; API key rotation dropping required scopes.","solutions":["Inspect the embedded {e} for the concrete HTTP/Bybit error code","Check the outstanding borrow amount for the coin and repay only up to it","Verify API key permissions for UTA spot margin repay","Retry on transient network/5xx errors; surface non-retryable rejections to the operator"],"exampleFix":"// before\nclient.no_convert_repay(coin, Some(\"100\".into())).await?;\n// after\nif let Err(e) = client.no_convert_repay(coin, Some(\"100\".into())).await {\n    log::error!(\"repay {coin} failed: {e}\");\n    // fetch outstanding liability and retry with a valid amount\n}","handlingStrategy":"try-catch","validationCode":"let liability = client.get_outstanding_borrow(coin).await?;\nif liability == 0 { return Ok(()); } // nothing to repay\nlet amt = amount.min(liability);","typeGuard":null,"tryCatchPattern":"if let Err(e) = client.no_convert_repay(coin, amount).await {\n    log::error!(\"repay {coin} failed: {e}\");\n    // re-query liability, adjust amount, retry once\n}","preventionTips":["Query outstanding liability before each repay","Never repay more than the current borrow","Keep repay permissions on the API key","Handle Bybit maintenance windows with backoff"],"tags":["rust","bybit","http","margin"],"backgroundTag":"api-request-failed","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"}