affaan-m/ECC · critical · anyhow::Error
ECC runner did not expose a process id
Error message
ECC runner did not expose a process id
What it means
After spawning the ECC runner as a background child process, the code calls child.id() to retrieve the OS process ID for tracking. If the child has already exited or the platform does not expose a PID, child.id() returns None and the function bails. Without a PID, the session manager cannot stop or monitor the runner.
Source
Thrown at ecc2/src/session/manager.rs:3027
.arg(session_id)
.arg("--task")
.arg(task)
.arg("--agent")
.arg(agent_type)
.arg("--cwd")
.arg(working_dir)
.stdin(Stdio::null())
.stdout(Stdio::null())
.stderr(Stdio::from(stderr_log));
configure_background_runner_command(&mut command);
let child = command
.spawn()
.with_context(|| format!("Failed to spawn ECC runner from {}", current_exe.display()))?;
child
.id()
.ok_or_else(|| anyhow::anyhow!("ECC runner did not expose a process id"))?;
Ok(())
}
fn background_runner_stderr_log_path(working_dir: &Path, session_id: &str) -> PathBuf {
working_dir
.join(".claude")
.join("ecc2")
.join("logs")
.join(format!("{session_id}.runner-stderr.log"))
}
#[cfg(windows)]
fn detached_creation_flags() -> u32 {
const DETACHED_PROCESS: u32 = 0x0000_0008;
const CREATE_NEW_PROCESS_GROUP: u32 = 0x0000_0200;
DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP
}
View on GitHub (pinned to 01e15490f0)
Solutions
- Verify the ECC runner executable exists and is runnable at the path returned by current_exe()
- Check stderr logs at the runner-stderr log path for immediate-exit errors
- Retry the spawn after confirming the executable is valid
- On platforms where PID is unreliable, consider using process groups or named locks instead
Defensive patterns
Strategy: try-catch
Try / catch
match spawn_ecc_runner(working_dir, session_id) {
Ok(()) => {},
Err(e) if e.to_string().contains("did not expose a process id") => {
tracing::error!("ECC runner exited immediately; check stderr log at {}",
background_runner_stderr_log_path(working_dir, session_id).display());
return Err(e);
}
Err(e) => return Err(e),
} Prevention
- Verify the ECC runner executable exists and runs before launching sessions
- Monitor stderr logs for immediate-exit errors after spawn
- Implement health checks that verify the runner PID is alive shortly after spawn
When it happens
Trigger: The spawned ECC runner child process exits immediately before child.id() is called, or the platform/runtime does not assign a PID to the spawned process.
Common situations: Runner executable is missing or broken, causing immediate exit. Platform limitation where std::process::Child does not expose a PID. The child was already waited on by another code path.
Related errors
- Claude Code did not expose a process id
- Spawned process did not expose a process id
- Command "${commandName}" terminated by signal ${result.signa
- ${command} ${args.join(' ')} failed: ${result.error.message}
- ${command} ${args.join(' ')} failed: ${(result.stderr || res
AI-assisted analysis of affaan-m/ECC@01e15490f0 (2026-08-13).
Data as JSON: /api/errors/f0b8cdcdf6576eba.
Report an issue: GitHub.