{"record":{"id":"f852c5df6c978b75","repo":"tonhowtf/omniget","slug":"writer-task-panicked","errorCode":null,"errorMessage":"Writer task panicked: {:?}","messagePattern":"Writer task panicked: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"src-tauri/omniget-core/src/core/hls_downloader.rs","lineNumber":399,"sourceCode":"                        Err(e) => {\n                            let key = e.to_string();\n                            let mut errs = errors_ref.lock().await;\n                            *errs.entry(key).or_insert(0) += 1;\n                            drop(errs);\n                            fail_ref.cancel();\n                        }\n                    }\n                }\n            })\n            .buffer_unordered(max_concurrent as usize)\n            .collect::<()>()\n            .await;\n\n        drop(seg_tx);\n\n        let writer_result = writer\n            .await\n            .map_err(|e| anyhow::anyhow!(\"Writer task panicked: {:?}\", e))?;\n\n        if cancel_token.is_cancelled() {\n            let _ = std::fs::remove_file(&part_path);\n            anyhow::bail!(\"Download cancelled by user\");\n        }\n\n        let errs = errors.lock().await;\n        if !errs.is_empty() {\n            let _ = std::fs::remove_file(&part_path);\n            let summary: Vec<String> = errs\n                .iter()\n                .map(|(msg, count)| {\n                    if *count > 1 {\n                        format!(\"{} (x{})\", msg, count)\n                    } else {\n                        msg.clone()\n                    }\n                })","sourceCodeStart":381,"sourceCodeEnd":417,"githubUrl":"https://github.com/tonhowtf/omniget/blob/8600b91f4246848bac346874daa9e61c1fc5677a/src-tauri/omniget-core/src/core/hls_downloader.rs#L381-L417","documentation":"Segments are written to the output part file by a spawned tokio task; download_media_playlist awaits its JoinHandle. If the writer task panicked (JoinError), this error is raised. A panic in the writer typically stems from an I/O bug or an unwrap inside the task, and it means the part file is incomplete.","triggerScenarios":"writer JoinHandle resolves with Err(JoinError) because the task panicked — e.g., unwrap on a poisoned mutex, file write returning an unexpected state, or an index bug on segment payloads.","commonSituations":"Disk full or file handle issues surfacing as a panic inside the writer; bug in segment ordering code (payload_start beyond buffer length); tokio runtime shutdown mid-task.","solutions":["Check the JoinError payload to find the panic message and location; fix the unwrap/panic inside the writer task.","Verify disk space and write permissions for part_path before starting the download.","Guard slicing like &segment_data[payload_start..] with length checks to avoid panics.","Clean up the part file and restart the download after fixing; the partial file is unusable."],"exampleFix":"// before\nlet writer_result = writer.await\n    .map_err(|e| anyhow::anyhow!(\"Writer task panicked: {:?}\", e))?;\n// after\nlet writer_result = writer.await.map_err(|e| {\n    let _ = std::fs::remove_file(&part_path);\n    anyhow::anyhow!(\"Writer task panicked: {e:?}\")\n})?;\nif let Err(e) = writer_result {\n    let _ = std::fs::remove_file(&part_path);\n    return Err(e);\n}","handlingStrategy":"try-catch","validationCode":"// Pre-check destination writability/space before spawning writer\nlet probe = std::fs::OpenOptions::new().write(true).create(true).open(&part_path);\nif let Err(e) = probe { anyhow::bail!(\"cannot write part file: {e}\"); }","typeGuard":null,"tryCatchPattern":"match writer.await {\n    Ok(Ok(())) => { /* success */ }\n    Ok(Err(e)) => { let _ = std::fs::remove_file(&part_path); bail!(\"writer io error: {e}\"); }\n    Err(join_err) => {\n        let _ = std::fs::remove_file(&part_path);\n        bail!(\"writer task panicked: {join_err:?}\");\n    }\n};","preventionTips":["Avoid unwrap()/expect() inside spawned writer tasks; return Results.","Check payload_start <= segment_data.len() before slicing.","Monitor disk space for long HLS downloads.","Delete the part file on any writer failure so restarts begin clean."],"tags":["tokio","panic","hls","writer-task"],"backgroundTag":"background-task-panicked","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"}