affaan-m/ECC · error
Claude Code did not expose a process id
Error message
Claude Code did not expose a process id
What it means
Same family as the runner-pid error but for the Claude Code agent process: child.id() returned None after spawning the agent binary. The manager needs the pid to stop/track the session, so None is converted into an anyhow error.
Solutions
- Verify agent_program exists and is executable before spawn
- Run the agent manually with the same args to see why it exits instantly
- Capture the spawn exit status and surface it instead of only the missing pid
Example fix
// before
child.id().ok_or_else(|| anyhow::anyhow!("Claude Code did not expose a process id"))
// after
let pid = child.id().with_context(|| format!("Claude Code exited immediately: {:?}", child.try_wait()))?; Defensive patterns
Strategy: try-catch
Validate before calling
if !agent_program.exists() {
anyhow::bail!("agent binary not found: {}", agent_program.display());
} Try / catch
match spawn_agent().await {
Ok(pid) => /* track session */,
Err(e) if e.to_string().contains("did not expose a process id") => {
eprintln!("Claude Code exited immediately; run it manually to see the error");
}
Err(e) => return Err(e),
} Prevention
- Smoke-test the agent command line outside the manager first
- Check binary permissions/executable bit
- Verify PATH/auth so the agent doesn't die at startup
When it happens
Trigger: Spawning the Claude Code agent executable where the Child handle's id() is None — the process already exited, or platform-specific pid exposure failed (notably Windows).
Common situations: agent_program path pointing at a wrapper that exits immediately; missing agent binary permissions causing instant death; Windows handle/AV interference.
Related errors
- ECC runner did not expose a process id
- Spawned process did not expose a process id
- Codex probe failed
- failed
- git add failed for
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/995fc3631260694d.
Report an issue: GitHub.
Appendix: source
Thrown at ecc2/src/session/manager.rs:3570
task,
session_id,
working_dir,
None,
);
let child = command
.stdout(Stdio::null())
.stderr(Stdio::null())
.spawn()
.with_context(|| {
format!(
"Failed to spawn Claude Code from {}",
agent_program.display()
)
})?;
child
.id()
.ok_or_else(|| anyhow::anyhow!("Claude Code did not expose a process id"))
}
async fn stop_session_with_options(
db: &StateStore,
id: &str,
cleanup_worktree: bool,
) -> Result<()> {
let session = resolve_session(db, id)?;
stop_session_recorded(db, &session, cleanup_worktree)
}
fn stop_session_recorded(db: &StateStore, session: &Session, cleanup_worktree: bool) -> Result<()> {
if let Some(pid) = session.pid {
kill_process(pid)?;
}
db.update_pid(&session.id, None)?;
db.update_state(&session.id, &SessionState::Stopped)?;View on GitHub (pinned to 8321021c54)