tonhowtf/omniget · error
Failed to start ffmpeg
Error message
Failed to start ffmpeg: {} What it means
convert() spawns the ffmpeg binary as a child process via crate::core::process::command. If spawn() fails — the binary is missing, not executable, or cannot be launched — the OS error is wrapped into this anyhow error. It indicates the conversion never started.
Solutions
- Install ffmpeg (apt install ffmpeg / brew install ffmpeg / choco install ffmpeg) or bundle it as a Tauri sidecar.
- Verify `ffmpeg -version` runs in the same environment the app executes in (check PATH for GUI vs shell).
- Check the binary's execute permission bit if ffmpeg is shipped alongside the app.
- Call is_ffmpeg_available() before convert and surface a clear setup message to the user.
Example fix
// before
let mut child = crate::core::process::command("ffmpeg")
.args(&args)
.spawn()
.map_err(|e| anyhow!("Failed to start ffmpeg: {}", e))?;
// after
if !is_ffmpeg_available().await {
anyhow::bail!("ffmpeg is not installed or not on PATH; install it or configure FFMPEG_PATH");
}
let mut child = crate::core::process::command("ffmpeg")
.args(&args)
.spawn()
.map_err(|e| anyhow!("Failed to start ffmpeg: {} (PATH={:?})", e, std::env::var("PATH")))?; Defensive patterns
Strategy: fallback
Validate before calling
// before calling convert/embed_metadata
if !is_ffmpeg_available().await {
return Err(anyhow!(
"ffmpeg is required: install it (apt/brew/choco install ffmpeg) or bundle as sidecar"
));
} Type guard
async fn ffmpeg_ready() -> bool {
tokio::process::Command::new("ffmpeg")
.arg("-version")
.output()
.await
.map(|o| o.status.success())
.unwrap_or(false)
} Try / catch
match convert(/* ... */).await {
Err(e) if e.to_string().contains("Failed to start ffmpeg") => {
ui::prompt_ffmpeg_install(); // guide user instead of raw error
}
other => other?,
} Prevention
- Check availability once at app startup and show a setup banner early
- For Tauri apps, ship ffmpeg as a sidecar and resolve its absolute path
- Never assume GUI process PATH equals developer shell PATH
When it happens
Trigger: Calling convert (or the download pipeline that uses it) when ffmpeg is not installed, not on PATH, or lacks execute permission in the target environment (e.g. bundled Tauri app without sidecar binaries).
Common situations: Clean CI/container images without ffmpeg; macOS/Windows packaging where the sidecar binary wasn't shipped; PATH differing between dev shell and GUI-launched app; antivirus/executable-permission blocks.
Related errors
AI-assisted analysis of tonhowtf/omniget@8600b91f42 (2026-09-12).
Data as JSON: /api/errors/2919cc4f35c221ba.
Report an issue: GitHub.
Appendix: source
Thrown at src-tauri/omniget-core/src/core/ffmpeg.rs:346
}
if let Some(ref extra) = opts.additional_output_args {
args.extend(extra.clone());
}
args.extend([
"-progress".to_string(),
"pipe:1".to_string(),
"-nostats".to_string(),
opts.output_path.clone(),
]);
let mut child = crate::core::process::command("ffmpeg")
.args(&args)
.stdout(std::process::Stdio::piped())
.stderr(std::process::Stdio::piped())
.spawn()
.map_err(|e| anyhow!("Failed to start ffmpeg: {}", e))?;
let stdout = child
.stdout
.take()
.ok_or_else(|| anyhow!("No stdout from ffmpeg"))?;
let reader = BufReader::new(stdout);
let mut lines = reader.lines();
let cancel = cancel_token.clone();
let progress = progress_tx.clone();
let line_reader = tokio::spawn(async move {
while let Ok(Some(line)) = lines.next_line().await {
if cancel.is_cancelled() {
break;
}
if let Some(us) = parse_out_time_us(&line) {
if total_duration_us > 0 {
let pct = (us as f64 / total_duration_us as f64 * 100.0).min(100.0);View on GitHub (pinned to 8600b91f42)