{"record":{"id":"9a640aed7fbc994e","repo":"jdx/mise","slug":"http-download-timed-out-after-for-attempt","errorCode":null,"errorMessage":"HTTP download timed out after {} for {} (attempt {}, {} bytes received; change with `http_download_timeout` or env `MISE_HTTP_DOWNLOAD_TIMEOUT`)","messagePattern":"HTTP download timed out after (.+?) for (.+?) \\(attempt (.+?), (.+?) bytes received; change with `http_download_timeout` or env `MISE_HTTP_DOWNLOAD_TIMEOUT`\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/http.rs","lineNumber":921,"sourceCode":"            let partial = partial.clone();\n            async move {\n                attempt.fetch_add(1, Ordering::Relaxed);\n                bytes_received.store(0, Ordering::Relaxed);\n                self.download_file_attempt(request_url, headers, &partial, pr, &bytes_received)\n                    .await\n            }\n        });\n\n        let metadata = match tokio::time::timeout(total_timeout, download).await {\n            Ok(result) => result?,\n            Err(_) => {\n                // A timeout cancels the transfer future before its normal cleanup\n                // runs. Loading the sidecar removes an unvalidated partial while\n                // preserving a resumable one.\n                if let Err(err) = partial.load() {\n                    debug!(\"failed to validate partial download after timeout: {err:#}\");\n                }\n                bail!(\n                    \"HTTP download timed out after {} for {} (attempt {}, {} bytes received; change with `http_download_timeout` or env `MISE_HTTP_DOWNLOAD_TIMEOUT`)\",\n                    format_duration(total_timeout),\n                    url,\n                    attempt.load(Ordering::Relaxed),\n                    bytes_received.load(Ordering::Relaxed),\n                )\n            }\n        };\n\n        // Complete the atomic rename after the cancellable transfer budget. A\n        // blocking task cannot be cancelled once it starts, so keeping it out\n        // of `timeout` prevents us from returning an error while it can still\n        // install the destination in the background.\n        let path = path.to_path_buf();\n        tokio::task::spawn_blocking(move || partial.persist(&path)).await??;\n        Ok(metadata)\n    }\n","sourceCodeStart":903,"sourceCodeEnd":939,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/http.rs#L903-L939","documentation":"HTTP downloads in src/http.rs enforce a total transfer timeout (http_download_timeout setting / MISE_HTTP_DOWNLOAD_TIMEOUT env). When the download exceeds that budget, the transfer future is cancelled, any partial download is validated/cleaned up, and this error reports the elapsed duration, URL, attempt number, and bytes received so far.","triggerScenarios":"A large artifact download takes longer than the configured total timeout — slow network, throttled mirror, huge file, or an unreasonably low timeout setting.","commonSituations":"Downloading multi-hundred-MB toolchains (Node, Swift, JDK) on slow links; corporate proxies throttling; default timeout too small for the file size; congested Wi-Fi or VPN.","solutions":["Increase the timeout: set MISE_HTTP_DOWNLOAD_TIMEOUT (or http_download_timeout in settings) to a larger duration","Check network throughput; switch to a faster mirror via MISE_*_MIRROR settings for the tool","Resume by retrying — partial downloads are preserved as resumable when valid","Verify no proxy/VPN is throttling the download; try a direct connection"],"exampleFix":"# shell\n# before\nexport MISE_HTTP_DOWNLOAD_TIMEOUT=30s\n# after\nexport MISE_HTTP_DOWNLOAD_TIMEOUT=600s","handlingStrategy":"try-catch","validationCode":"// size the timeout against expected artifact size and bandwidth\nlet size_mb = content_length / (1024 * 1024);\nlet needed = size_mb as u64 * 4; // seconds/MB on a slow link\nstd::env::set_var(\"MISE_HTTP_DOWNLOAD_TIMEOUT\", format!(\"{}s\", needed.max(300)));","typeGuard":null,"tryCatchPattern":"match download(url, dest).await {\n    Err(e) if e.to_string().contains(\"timed out\") => {\n        eprintln!(\"download timed out; retrying with larger timeout / from mirror\");\n        download_with_fallback_mirror(url, dest).await?; // resumes from partial\n    }\n    other => other?,\n}","preventionTips":["Set MISE_HTTP_DOWNLOAD_TIMEOUT generously for large toolchains","Use fast regional mirrors (MISE_*_MIRROR) for big artifacts","Ensure partial-download resume keeps working: don't wipe mise's cache mid-download"],"tags":["http","download","timeout","network"],"backgroundTag":"request-timeout","analyzedSha":"afd2eddd3a50c16190efc1c7e94404b48f72af57","analyzedAt":"2026-09-09T01:38:25.179Z","contentChangedAt":"2026-09-09T01:38:25.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}