windmill-labs/windmill · error
Cannot take stdout from uv_install_proccess
Error message
Cannot take stdout from uv_install_proccess
What it means
The stdout counterpart of the stderr failure: after spawning `uv pip install`, the code calls .stdout().take() on the child to get the piped stdout handle for async draining. take() returns None when stdout was not spawned as piped or was already taken, and the code raises "Cannot take stdout from uv_install_proccess".
Source
Thrown at backend/windmill-worker/src/python_executor.rs:3002
),
&conn,
)
.await;
pids.lock().await.get_mut(i).and_then(|e| e.take());
return Err(Error::from(e));
}
};
let (mut stderr_buf, mut stdout_buf) = Default::default();
let (mut stderr_pipe, mut stdout_pipe) = (
uv_install_proccess
.stderr()
.take()
.ok_or(anyhow!("Cannot take stderr from uv_install_proccess"))?,
uv_install_proccess
.stdout()
.take()
.ok_or(anyhow!("Cannot take stdout from uv_install_proccess"))?
);
let (stderr_future, stdout_future) = (
stderr_pipe.read_to_string(&mut stderr_buf),
stdout_pipe.read_to_string(&mut stdout_buf)
);
if let Some(pid) = pids.lock().await.get_mut(i) {
*pid = uv_install_proccess.id();
#[cfg(unix)]
if let Err(e) = uv_install_proccess
.id()
.ok_or(Error::InternalErr(format!(
"failed to get PID for python installation process: {}",
&req
)))
.and_then(|pid| write_file(
&format!("/proc/{pid}"),
"oom_score_adj",View on GitHub (pinned to e474e8803c)
Solutions
- Ensure the uv Command sets .stdout(Stdio::piped()) (and .stderr(Stdio::piped())) at spawn time.
- Verify the pipe handles are taken exactly once per child; don't reuse the Child across install attempts.
- If uv is wrapped or the executor was patched, restore the original spawn options.
- Run a known-good Windmill build to confirm it's a local modification, then fix or report the regression.
Example fix
// before
let mut uv_install_proccess = Command::new("uv").args([...]).spawn()?;
// after
use std::process::Stdio;
let mut uv_install_proccess = Command::new("uv")
.args([...])
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()?; Defensive patterns
Strategy: fallback
Try / catch
match child.stdout.take() {
Some(p) => p,
None => return Err(anyhow!("uv spawn must set stdout(Stdio::piped()); check executor Command construction")),
} Prevention
- Configure both stdout and stderr as piped at spawn time, never later
- Treat the Child as single-use: one take per pipe, respawn for retries
- Regression-test the subprocess spawn path whenever the executor changes
When it happens
Trigger: The uv install child was spawned without Stdio::piped() for stdout, or another code path already called .stdout().take() on the same Child before this line runs.
Common situations: Executor code changes that dropped piped stdout; double-consumption of the child's stdout (e.g. a retry path reusing the same Child); a custom uv wrapper that changes how the process is spawned; Windmill version regressions.
Related errors
- Cannot take stderr from uv_install_proccess
- uv pip install was canceled
- ${what} failed:\n${output}
- failed to execute replace_ephemeral command: {}
- Cannot list python versions, is uv (0.5.19 and newer) instal
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/bae4cb28b3a13cb2.
Report an issue: GitHub.