affaan-m/ECC · error · anyhow::Error
Child stderr was not piped
Error message
Child stderr was not piped
What it means
Same invariant as stdout: capture_command_output requires piped stderr, and child.stderr.take() returned None. The child is killed and waited before the error is raised, indicating the Command was built without Stdio::piped for stderr.
Solutions
- Spawn the child process with stderr set to piped before reading it.
- Ensure no earlier code consumed or detached the stderr handle.
Defensive patterns
Strategy: type-guard
When it happens
Trigger: Thrown at ecc2/src/session/runtime.rs:166 when the library encounters an invalid state.
Common situations: See trigger scenarios.
AI-assisted analysis of affaan-m/ECC@06c5e118c4 (2026-08-18).
Data as JSON: /api/errors/eacf1222c27f8a18.
Report an issue: GitHub.
Appendix: source
Thrown at ecc2/src/session/runtime.rs:166
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()
.with_context(|| format!("Failed to start process for session {}", session_id))?;
let stdout = match child.stdout.take() {
Some(stdout) => stdout,
None => {
let _ = child.kill().await;
let _ = child.wait().await;
anyhow::bail!("Child stdout was not piped");
}
};
let stderr = match child.stderr.take() {
Some(stderr) => stderr,
None => {
let _ = child.kill().await;
let _ = child.wait().await;
anyhow::bail!("Child stderr was not piped");
}
};
let pid = child
.id()
.ok_or_else(|| anyhow::anyhow!("Spawned process did not expose a process id"))?;
db_writer.update_pid(Some(pid)).await?;
db_writer.update_state(SessionState::Running).await?;
db_writer.touch_heartbeat().await?;
let heartbeat_writer = db_writer.clone();
let heartbeat_task = tokio::spawn(async move {
let mut ticker = time::interval(heartbeat_interval);
ticker.set_missed_tick_behavior(MissedTickBehavior::Delay);
loop {
ticker.tick().await;
if heartbeat_writer.touch_heartbeat().await.is_err() {
break;View on GitHub (pinned to 06c5e118c4)