{"record":{"id":"e47a0984a61bab3e","repo":"tonhowtf/omniget","slug":"write-error-disk-full","errorCode":null,"errorMessage":"Write error (disk full?): {}","messagePattern":"Write error \\(disk full\\?\\): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src-tauri/omniget-core/src/core/direct_downloader.rs","lineNumber":548,"sourceCode":"\n    let mut last_emit = std::time::Instant::now();\n    let mut speed_anchor_bytes = downloaded;\n    let mut speed_anchor_time = std::time::Instant::now();\n    let mut speed_ema: f64 = 0.0;\n\n    loop {\n        if let Some(token) = cancel {\n            if token.is_cancelled() {\n                file.flush()?;\n                return Err(anyhow!(\"Download cancelled\"));\n            }\n        }\n\n        let chunk_result = tokio::time::timeout(CHUNK_TIMEOUT, stream.next()).await;\n        match chunk_result {\n            Ok(Some(Ok(chunk))) => {\n                file.write_all(&chunk)\n                    .map_err(|e| anyhow!(\"Write error (disk full?): {}\", e))?;\n                downloaded += chunk.len() as u64;\n\n                if last_emit.elapsed() >= std::time::Duration::from_millis(250) {\n                    let dt = speed_anchor_time.elapsed().as_secs_f64();\n                    if dt >= 0.2 {\n                        let instant = (downloaded.saturating_sub(speed_anchor_bytes)) as f64 / dt;\n                        speed_ema = if speed_ema > 0.0 {\n                            speed_ema * 0.6 + instant * 0.4\n                        } else {\n                            instant\n                        };\n                        speed_anchor_bytes = downloaded;\n                        speed_anchor_time = std::time::Instant::now();\n                    }\n                    let speed = (speed_ema > 0.0).then_some(speed_ema);\n                    let (percent, eta) = match total_size {\n                        Some(total) if total > 0 => {\n                            let pct = (downloaded as f64 / total as f64) * 100.0;","sourceCodeStart":530,"sourceCodeEnd":566,"githubUrl":"https://github.com/tonhowtf/omniget/blob/8600b91f4246848bac346874daa9e61c1fc5677a/src-tauri/omniget-core/src/core/direct_downloader.rs#L530-L566","documentation":"Each downloaded chunk is written to the .part file with file.write_all; if the OS write fails, the downloader wraps the std::io::Error with this message. The 'disk full?' hint reflects the most common cause — insufficient free space — though it can also be I/O errors, quota limits, or a removed file handle.","triggerScenarios":"file.write_all(&chunk) returned Err while streaming: ENOSPC (no space left on device), EDQUOT (quota exceeded), EIO (disk error), or writing to a file/destination that was deleted or on a disconnected mount (e.g. unmounted external drive).","commonSituations":"Downloading multi-GB files to a nearly full disk; user quota limits on network shares; the destination drive (USB/NAS) disconnecting mid-download; antivirus or backup software locking the file.","solutions":["Free up disk space on the destination volume (check with df) and resume — the .part file allows resuming","Verify the destination path's volume is mounted and writable","Check disk health and filesystem errors if EIO recurs (dmesg / SMART)","Reduce concurrency if parallel downloads are exhausting space or file locks","Move the download target to a volume with enough space for the full file size before restarting"],"exampleFix":"// before: starting a download without a space check\nlet resp = client.get(url).send().await?;\ndownload(resp, &part_path).await?;\n// after: pre-flight free-space check\nlet expected = content_length(&resp);\nlet available = fs2::available_space(parent_dir_of(&part_path))?;\nif available < expected + 100 * 1024 * 1024 {\n    anyhow::bail!(\"Not enough disk space: need {}, have {}\", expected, available);\n}\ndownload(resp, &part_path).await?;","handlingStrategy":"validation","validationCode":"let needed = content_length_hint; // from HEAD/Content-Length\nlet free = fs2::available_space(&dest_dir)?;\nif free < needed + margin { bail!(\"insufficient disk space: need {}, free {}\", needed, free); }","typeGuard":null,"tryCatchPattern":"match download(url, path).await {\n    Err(e) if e.to_string().starts_with(\"Write error (disk full?)\") => {\n        free_up_space_or_change_target()?;\n        resume_download(url, path).await?; // .part allows resuming\n    }\n    r => r?,\n}","preventionTips":["Check available space (file size from Content-Length) before starting large downloads","Point temp/.part files at a volume with guaranteed free space","Monitor disk space during long downloads and pause before ENOSPC","Verify external/NAS volumes remain mounted and writable for the download's duration"],"tags":["io","filesystem","disk-full","write-error","download"],"backgroundTag":"file-write-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"}