tonhowtf/omniget · error

No stdout

Error message

No stdout

What it means

Raised when `child.stdout.take()` returns None after the yt-dlp child process was spawned. Stdout was configured as piped at spawn time, so take() returning None means the pipe handle is missing — effectively an internal invariant violation that should be impossible under normal operation (e.g. the handle was already taken or the child was reconfigured).

Solutions

  1. Ensure `cmd.stdout(Stdio::piped())` is set before spawn and stdout is taken exactly once.
  2. Restart the download; if reproducible, reinstall/update the app (fork or modified binary).
  3. Report as a bug with logs if it reproduces on an unmodified install.

Example fix

// before
let mut child = cmd.spawn()?;
let stdout = child.stdout.take().ok_or_else(|| anyhow!("No stdout"))?;
// after
use std::process::Stdio;
cmd.stdout(Stdio::piped()).stderr(Stdio::piped());
let mut child = cmd.spawn()?;
let stdout = child.stdout.take().ok_or_else(|| anyhow!("No stdout: pipe not configured"))?;
Defensive patterns

Strategy: type-guard

Type guard

fn take_stdout(child: &mut tokio::process::Child) -> anyhow::Result<tokio::process::ChildStdout> {
    child.stdout.take().ok_or_else(|| anyhow!("stdout was not piped or already taken"))
}

Try / catch

match child.stdout.take() {
    Some(out) => { /* proceed */ }
    None => { tracing::error!("stdout pipe missing — spawn configuration bug"); return Err(anyhow!("No stdout")); }
}

Prevention

When it happens

Trigger: Reaching ytdlp.rs:3470 after a spawn where stdout was not actually piped, or where stdout was already taken by other code; practically only occurs if the spawn setup was modified or a different code path constructed the command.

Common situations: Custom forks/patches to the spawn configuration; spawning via a shim where the parent lost the pipe; extremely rare OS-level pipe allocation failure.

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/d117dc67ef064d34. Report an issue: GitHub.

Appendix: source

Thrown at src-tauri/omniget-core/src/core/ytdlp.rs:3470

            .stdout(Stdio::piped())
            .stderr(Stdio::piped())
            .kill_on_drop(true);
        let mut child = cmd
            .spawn()
            .map_err(|e| anyhow!("Failed to start yt-dlp: {}", e))?;
        let registered_download_id = log_hook::current_download_id();
        if let (Some(download_id), Some(pid)) = (registered_download_id, child.id()) {
            register_download_process(download_id, pid);
        }
        tracing::debug!(
            "[perf] download_video: yt-dlp process spawned at {:?} (attempt {})",
            _timer_start.elapsed(),
            attempt + 1
        );

        let _ = progress.send(ProgressUpdate::percent(-2.0)).await;

        let stdout = child.stdout.take().ok_or_else(|| anyhow!("No stdout"))?;
        let stderr_pipe = child.stderr.take().ok_or_else(|| anyhow!("No stderr"))?;

        let lines = BufReader::new(stdout).lines();

        let captured_path: Arc<Mutex<Option<PathBuf>>> = Arc::new(Mutex::new(None));
        let line_reader = spawn_stdout_reader(
            lines,
            progress.clone(),
            captured_path.clone(),
            log_hook::current_download_id(),
            is_audio_only,
            _timer_start,
            Some(boot_slot.clone()),
        );

        let stderr_log_id = log_hook::current_download_id();
        let stderr_boot_slot = boot_slot.clone();
        let stderr_reader = tokio::spawn(async move {

View on GitHub (pinned to 8600b91f42)