{"record":{"id":"d117dc67ef064d34","repo":"tonhowtf/omniget","slug":"no-stdout","errorCode":null,"errorMessage":"No stdout","messagePattern":"No stdout","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src-tauri/omniget-core/src/core/ytdlp.rs","lineNumber":3470,"sourceCode":"            .stdout(Stdio::piped())\n            .stderr(Stdio::piped())\n            .kill_on_drop(true);\n        let mut child = cmd\n            .spawn()\n            .map_err(|e| anyhow!(\"Failed to start yt-dlp: {}\", e))?;\n        let registered_download_id = log_hook::current_download_id();\n        if let (Some(download_id), Some(pid)) = (registered_download_id, child.id()) {\n            register_download_process(download_id, pid);\n        }\n        tracing::debug!(\n            \"[perf] download_video: yt-dlp process spawned at {:?} (attempt {})\",\n            _timer_start.elapsed(),\n            attempt + 1\n        );\n\n        let _ = progress.send(ProgressUpdate::percent(-2.0)).await;\n\n        let stdout = child.stdout.take().ok_or_else(|| anyhow!(\"No stdout\"))?;\n        let stderr_pipe = child.stderr.take().ok_or_else(|| anyhow!(\"No stderr\"))?;\n\n        let lines = BufReader::new(stdout).lines();\n\n        let captured_path: Arc<Mutex<Option<PathBuf>>> = Arc::new(Mutex::new(None));\n        let line_reader = spawn_stdout_reader(\n            lines,\n            progress.clone(),\n            captured_path.clone(),\n            log_hook::current_download_id(),\n            is_audio_only,\n            _timer_start,\n            Some(boot_slot.clone()),\n        );\n\n        let stderr_log_id = log_hook::current_download_id();\n        let stderr_boot_slot = boot_slot.clone();\n        let stderr_reader = tokio::spawn(async move {","sourceCodeStart":3452,"sourceCodeEnd":3488,"githubUrl":"https://github.com/tonhowtf/omniget/blob/8600b91f4246848bac346874daa9e61c1fc5677a/src-tauri/omniget-core/src/core/ytdlp.rs#L3452-L3488","documentation":"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).","triggerScenarios":"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.","commonSituations":"Custom forks/patches to the spawn configuration; spawning via a shim where the parent lost the pipe; extremely rare OS-level pipe allocation failure.","solutions":["Ensure `cmd.stdout(Stdio::piped())` is set before spawn and stdout is taken exactly once.","Restart the download; if reproducible, reinstall/update the app (fork or modified binary).","Report as a bug with logs if it reproduces on an unmodified install."],"exampleFix":"// before\nlet mut child = cmd.spawn()?;\nlet stdout = child.stdout.take().ok_or_else(|| anyhow!(\"No stdout\"))?;\n// after\nuse std::process::Stdio;\ncmd.stdout(Stdio::piped()).stderr(Stdio::piped());\nlet mut child = cmd.spawn()?;\nlet stdout = child.stdout.take().ok_or_else(|| anyhow!(\"No stdout: pipe not configured\"))?;","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"fn take_stdout(child: &mut tokio::process::Child) -> anyhow::Result<tokio::process::ChildStdout> {\n    child.stdout.take().ok_or_else(|| anyhow!(\"stdout was not piped or already taken\"))\n}","tryCatchPattern":"match child.stdout.take() {\n    Some(out) => { /* proceed */ }\n    None => { tracing::error!(\"stdout pipe missing — spawn configuration bug\"); return Err(anyhow!(\"No stdout\")); }\n}","preventionTips":["Always set Stdio::piped() for stdout immediately before spawn.","Take each pipe handle exactly once; centralize take logic in a helper.","Add a debug assertion that stdout is Some right after spawn in tests."],"tags":["rust","process-pipe","ytdlp","invariant"],"backgroundTag":"internal-invariant-violation","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"}