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
- Verify the spawn chain still includes .stdout(std::process::Stdio::piped()) exactly once.
- Ensure no other code calls child.stdout.take() before convert reads it.
- Refactor to construct the Command inside convert rather than passing a pre-configured Child.
- 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
- Keep Stdio::piped() configuration adjacent to spawn in the same function
- Write a unit test asserting the spawned command's stdout is piped
- Take child.stdout exactly once, immediately after spawn
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
- MB não cabem s de vídeo — aumente o alvo ou encurte o clipe
- a janela de corte ficou vazia — o vídeo tem
- alvo pequeno demais para
- {}
- concat falhou
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)