{"record":{"id":"a3166997fdf84b4e","repo":"tonhowtf/omniget","slug":"ffmpeg-process-failed","errorCode":null,"errorMessage":"ffmpeg process failed: {}","messagePattern":"ffmpeg process failed: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"src-tauri/omniget-core/src/core/ffmpeg.rs","lineNumber":374,"sourceCode":"    let progress = progress_tx.clone();\n    let line_reader = tokio::spawn(async move {\n        while let Ok(Some(line)) = lines.next_line().await {\n            if cancel.is_cancelled() {\n                break;\n            }\n            if let Some(us) = parse_out_time_us(&line) {\n                if total_duration_us > 0 {\n                    let pct = (us as f64 / total_duration_us as f64 * 100.0).min(100.0);\n                    let _ = progress.send(ProgressUpdate::percent(pct)).await;\n                }\n            }\n        }\n    });\n\n    let result = tokio::select! {\n        status = child.wait() => {\n            let _ = line_reader.await;\n            status.map_err(|e| anyhow!(\"ffmpeg process failed: {}\", e))\n        }\n        _ = cancel_token.cancelled() => {\n            let _ = child.kill().await;\n            let _ = line_reader.await;\n            return Ok(ConversionResult {\n                success: false,\n                output_path: opts.output_path.clone(),\n                file_size_bytes: 0,\n                duration_seconds: 0.0,\n                error: Some(\"Conversion cancelled\".to_string()),\n            });\n        }\n    };\n\n    match result {\n        Ok(status) if status.success() => {\n            let _ = progress_tx.send(ProgressUpdate::percent(100.0)).await;\n            let meta = std::fs::metadata(output_path);","sourceCodeStart":356,"sourceCodeEnd":392,"githubUrl":"https://github.com/tonhowtf/omniget/blob/8600b91f4246848bac346874daa9e61c1fc5677a/src-tauri/omniget-core/src/core/ffmpeg.rs#L356-L392","documentation":"convert() waits for the ffmpeg child process while streaming its stdout for progress. If child.wait() itself errors (the process could not be waited on — usually because it was already reaped or the runtime was interrupted), the error is wrapped into this anyhow error. Note this is a wait error, not a non-zero exit status.","triggerScenarios":"Calling convert in an environment where the child is killed/reaped externally before wait() completes, or the tokio runtime drops/shuts down while waiting; also SIGKILL of the parent causing handle invalidation.","commonSituations":"Long conversions in apps that are suspended or terminated; double-cancel paths racing with wait(); sandboxed environments that forbid waiting on children.","solutions":["Ensure cancel_token is the only mechanism that terminates ffmpeg (avoid killing the child elsewhere).","Keep the tokio runtime alive until convert's future completes; don't abort the task holding it.","Check exit status separately: if wait() succeeds with a non-zero code, report stderr, not this error.","Log whether a cancellation/select race occurred when this fires."],"exampleFix":"// before\nstatus = child.wait() => {\n    let _ = line_reader.await;\n    status.map_err(|e| anyhow!(\"ffmpeg process failed: {}\", e))\n}\n// after\nstatus = child.wait() => {\n    let _ = line_reader.await;\n    let status = status.map_err(|e| anyhow!(\"ffmpeg process failed: {}\", e))?;\n    if !status.success() {\n        anyhow::bail!(\"ffmpeg exited with {}: {}\", status, stderr_snapshot);\n    }\n    Ok(())\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"match convert(/* ... */).await {\n    Err(e) if e.to_string().contains(\"ffmpeg process failed\") => {\n        // wait() failed: likely external kill or runtime teardown\n        log::error!(\"ffmpeg wait error (not an ffmpeg exit failure): {e}\");\n        mark_job_interrupted(job_id);\n    }\n    other => other?,\n}","preventionTips":["Use only the cancel token to stop ffmpeg; don't kill the child elsewhere","Hold the tokio runtime open until conversion futures resolve","Distinguish wait() errors from non-zero exit codes in error handling"],"tags":["ffmpeg","process-wait","tokio","cancellation"],"backgroundTag":"process-termination-failed","analyzedSha":"8600b91f4246848bac346874daa9e61c1fc5677a","analyzedAt":"2026-09-12T14:29:19.317Z","contentChangedAt":"2026-09-12T14:29:19.317Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}