tonhowtf/omniget · error

No stdout from ffmpeg

Error message

No stdout from ffmpeg

What it means

After spawning ffmpeg, convert() takes the piped stdout handle. If the handle is missing (Stdio::piped() was not applied or was already consumed), it fails with this error. In practice this is an internal invariant: the spawn above always pipes stdout, so this fires only if that contract is broken.

Solutions

  1. Verify the spawn chain still includes .stdout(std::process::Stdio::piped()) exactly once.
  2. Ensure no other code calls child.stdout.take() before convert reads it.
  3. Refactor to construct the Command inside convert rather than passing a pre-configured Child.
  4. Treat it as a bug report if it reproduces: file with the spawn configuration in use.

Example fix

// before
let stdout = child
    .stdout
    .take()
    .ok_or_else(|| anyhow!("No stdout from ffmpeg"))?;
// after
let stdout = child.stdout.take().ok_or_else(|| {
    anyhow!(
        "No stdout from ffmpeg: stdout was not piped or was already taken (internal config bug)"
    )
})?;
Defensive patterns

Strategy: type-guard

Type guard

fn piped_child(child: &std::process::Child) -> Result<&std::process::Child, String> {
    if child.stdout.is_some() { Ok(child) } else { Err("child stdout is not piped".into()) }
}

Try / catch

match convert(/* ... */).await {
    Err(e) if e.to_string().contains("No stdout from ffmpeg") => {
        // internal bug: report to maintainers with the spawn configuration
        report_internal_bug(e);
    }
    other => other?,
}

Prevention

When it happens

Trigger: Essentially only from a code regression where .stdout(std::process::Stdio::piped()) is removed or a Child is reused/standard streams taken twice before convert reads it.

Common situations: Refactoring the spawn chain and accidentally dropping the piped stdout; wrapping the command in a helper that sets its own stdio config; tests mocking the process without a stdout pipe.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of tonhowtf/omniget@8600b91f42 (2026-09-12). Data as JSON: /api/errors/01718d8788d34b36. Report an issue: GitHub.

Appendix: source

Thrown at src-tauri/omniget-core/src/core/ffmpeg.rs:351

    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);
                    let _ = progress.send(ProgressUpdate::percent(pct)).await;
                }
            }
        }
    });

View on GitHub (pinned to 8600b91f42)