{"record":{"id":"5c237fa25da03ab3","repo":"windmill-labs/windmill","slug":"failed-to-read-repository-archive-e","errorCode":null,"errorMessage":"Failed to read repository archive: {e}","messagePattern":"Failed to read repository archive: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"backend/windmill-worker/src/ansible_executor.rs","lineNumber":483,"sourceCode":"            return Err(error::Error::BadRequest(format!(\n                \"Failed to download `{}` ({}): {}\",\n                resource, status, body\n            )));\n        }\n\n        let commit = response\n            .headers()\n            .get(\"x-commit-sha\")\n            .and_then(|v| v.to_str().ok())\n            .unwrap_or(\"unknown\")\n            .to_string();\n\n        // Written out chunk by chunk: a repository is arbitrarily large, and\n        // holding one in the worker's memory would take every job on it down.\n        let mut file = tokio::fs::File::create(&download_archive).await?;\n        let mut stream = response.bytes_stream();\n        while let Some(chunk) = stream.next().await {\n            let chunk = chunk.map_err(|e| anyhow!(\"Failed to read repository archive: {e}\"))?;\n            file.write_all(&chunk).await?;\n        }\n        file.flush().await?;\n        drop(file);\n\n        // Dropping the join handle detaches the blocking task rather than\n        // stopping it, so the flag is what a cancelled job uses to reach the\n        // extraction loop. The guard sets it when this future is dropped.\n        let aborted = std::sync::Arc::new(std::sync::atomic::AtomicBool::new(false));\n        let _abort_on_drop = AbortOnDrop(aborted.clone());\n        let unpack_archive = download_archive.clone();\n        tokio::task::spawn_blocking(move || {\n            unpack_repo_archive(&unpack_archive, &download_target, &aborted)\n        })\n        .await\n        .map_err(|e| anyhow!(\"Failed to extract repository archive: {e}\"))??;\n\n        Ok(commit)","sourceCodeStart":465,"sourceCodeEnd":501,"githubUrl":"https://github.com/windmill-labs/windmill/blob/e474e8803ce2ff5c2df09a58dab51d45f5c922ca/backend/windmill-worker/src/ansible_executor.rs#L465-L501","documentation":"While streaming a repository archive download to disk chunk by chunk, one HTTP chunk failed to arrive (reqwest error wrapped in anyhow). The download is aborted so a partial archive is never extracted.","triggerScenarios":"Network interruption, proxy timeout, or the git/archive server closing the connection mid-stream while the worker streams response.bytes_stream().","commonSituations":"Large repos over flaky networks; corporate proxies with short idle timeouts; git host rate-limiting or resetting connections.","solutions":["Retry the job — the code deletes partial state on failure","Check network stability/proxy timeouts between worker and the git host","Reduce archive size (shallow/subset repos) if the host truncates large transfers","Verify the archive URL is still valid and the token hasn't expired mid-transfer"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"curl -sSI \"$ARCHIVE_URL\" | head -n1  # check reachability before streaming\ndf -h \"$DOWNLOAD_DIR\"                  # ensure disk space","typeGuard":null,"tryCatchPattern":"let mut attempts = 0;\nloop {\n    match fetch_repo_archive(...).await {\n        Err(e) if e.to_string().contains(\"Failed to read repository archive\") && attempts < 2 => {\n            attempts += 1;\n            tokio::time::sleep(Duration::from_secs(5 * attempts)).await;\n        }\n        other => { other?; break; }\n    }\n}","preventionTips":["Retry large downloads; keep per-chunk failure handling","Check proxy/idle-timeout settings for long transfers","Monitor worker network stability to the git host","Ensure archive URL tokens are valid for the whole transfer"],"tags":["rust","network","streaming","download"],"backgroundTag":"download-stream-interrupted","analyzedSha":"e474e8803ce2ff5c2df09a58dab51d45f5c922ca","analyzedAt":"2026-09-03T12:38:19.024Z","contentChangedAt":"2026-09-03T12:38:19.024Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}