{"record":{"id":"c44c427361ed60ca","repo":"tonhowtf/omniget","slug":"download-stream-error","errorCode":null,"errorMessage":"Download stream error: {}","messagePattern":"Download stream error: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src-tauri/omniget-core/src/core/direct_downloader.rs","lineNumber":593,"sourceCode":"                                .min(95.0),\n                            None,\n                        ),\n                    };\n                    let _ = progress_tx\n                        .send(ProgressUpdate::rich(\n                            percent,\n                            Some(downloaded),\n                            total_size.filter(|t| *t > 0),\n                            speed,\n                            eta,\n                        ))\n                        .await;\n                    last_emit = std::time::Instant::now();\n                }\n            }\n            Ok(Some(Err(e))) => {\n                file.flush()?;\n                return Err(anyhow!(\"Download stream error: {}\", e));\n            }\n            Ok(None) => break,\n            Err(_) => {\n                file.flush()?;\n                return Err(anyhow!(\n                    \"Download timeout — no data received for 30 seconds\"\n                ));\n            }\n        }\n    }\n\n    file.flush()?;\n    Ok(())\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;","sourceCodeStart":575,"sourceCodeEnd":611,"githubUrl":"https://github.com/tonhowtf/omniget/blob/8600b91f4246848bac346874daa9e61c1fc5677a/src-tauri/omniget-core/src/core/direct_downloader.rs#L575-L611","documentation":"While reading the response body stream, a chunk arrived as Ok(Some(Err(e))) — i.e. reqwest/hyper reported a mid-stream network error. The downloader flushes the partial file (so the .part can be resumed later) and returns the underlying transport error wrapped with this message. Distinguish it from the separate timeout arm, which fires when no chunk arrives at all within CHUNK_TIMEOUT (30s).","triggerScenarios":"The HTTP connection broke mid-body: server closed the connection prematurely (incomplete chunked encoding), TCP reset, TLS handshake/alert mid-stream, proxy dropped the connection, or a reqwest::Error from hyper while polling stream.next().","commonSituations":"Flaky Wi-Fi or mobile networks dropping long downloads; CDN origin closing idle-but-active connections; VPN/proxy interruptions; server-side connection limits killing long transfers; HTTP/2 GOAWAY from the server.","solutions":["Simply retry: download_attempt's retry logic resumes from the flushed .part file via the Range header","Enable/verify resume support — a valid .part file turns mid-stream drops into cheap recoveries","If errors recur on the same host, try HTTP/1.1 (disable HTTP/2) or route around a failing proxy","Check network stability (VPN, firewall, mobile handoff) for repeated resets","Add your own backoff around the whole download call if the network is known-unreliable"],"exampleFix":"// before: single-shot download fails on any blip\nsingle_stream(&client, url, &part_path, cancel).await?;\n// after: rely on resumable retries\nlet mut attempt = 0;\nloop {\n    match single_stream(&client, url, &part_path, cancel).await {\n        Ok(()) => break,\n        Err(e) if e.to_string().starts_with(\"Download stream error\") && attempt < 5 => {\n            attempt += 1;\n            tokio::time::sleep(Duration::from_secs(2u64.pow(attempt))).await; // resume from .part\n        }\n        Err(e) => return Err(e),\n    }\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"match download(url, path).await {\n    Err(e) if e.to_string().starts_with(\"Download stream error\") => {\n        // connection broke mid-stream; .part was flushed, so retry resumes via Range\n        retry_with_backoff(|| download(url, path), max_retries = 5).await?;\n    }\n    r => r?,\n}","preventionTips":["Keep resume (.part + Range) enabled so mid-stream drops are cheap to recover","Prefer wired/stable connections for very large transfers; avoid VPN/proxy paths that drop idle connections","Set reasonable retry counts with exponential backoff around the whole download","If a host persistently drops streams, try forcing HTTP/1.1 or a mirror URL"],"tags":["network","stream","connection-dropped","reqwest","download"],"backgroundTag":"network-request-failed","analyzedSha":"8600b91f4246848bac346874daa9e61c1fc5677a","analyzedAt":"2026-09-12T14:29:19.317Z","contentChangedAt":"2026-09-12T14:29:19.317Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}