Hmbown/CodeWhale · error · anyhow::Error
tmux session {session} remains active after kill-session ({s
Error message
tmux session {session} remains active after kill-session ({status}) What it means
stop_tmux_session sends kill-session and then re-checks tmux_session_state; if the session still reports Present it bails with the kill's exit status included. The follow-up absence check is deliberately the source of truth (a nonzero kill alone can be benign when the process exits in the same instant), so this error means the session verifiably survived the kill.
Source
Thrown at crates/lane/src/runtime.rs:610
)
}
fn stop_tmux_session(socket: &Path, session: &str) -> Result<()> {
let status = tmux_command(socket)
.args(["kill-session", "-t", session])
.stdout(Stdio::null())
.stderr(Stdio::null())
.status()
.with_context(|| format!("kill tmux session {session}"))?;
match tmux_session_state(socket, session).with_context(|| {
format!(
"confirm tmux session {session} on {} stopped after kill-session ({status})",
socket.display()
)
})? {
TmuxSessionState::Absent => {}
TmuxSessionState::Present => {
bail!("tmux session {session} remains active after kill-session ({status})")
}
}
// A nonzero kill can be benign when the process and session exited in the
// same instant. The explicit absence check above is the source of truth.
Ok(())
}
fn tmux_log_proxy_command(
proxy: &Path,
command: &[String],
log_path: &Path,
receipt_path: &Path,
receipt_tmp_path: &Path,
environment_path: Option<&Path>,
lane_id: &str,
) -> String {
let mut argv = vec![
proxy.display().to_string(),View on GitHub (pinned to 0c42157ee5)
Solutions
- Identify what re-creates the session: tmux -S <socket> list-sessions before/after the kill, and check for respawn/supervisor scripts
- Stop the re-creating process first, then stop the lane again
- If session names collide between managers, give lanes distinct session name prefixes
- Check the status value in the message — a failing kill-session plus survival usually means a permissions problem on the socket
Defensive patterns
Strategy: retry
Try / catch
for attempt in 0..3 {
match stop_tmux_session(&socket, &session) {
Ok(()) => break,
Err(err) if attempt < 2 && err.to_string().contains("remains active") => {
std::thread::sleep(std::time::Duration::from_millis(200)); // re-creator may finish
continue;
}
Err(err) => return Err(err),
}
} Prevention
- Do not auto-respawn lane sessions from shell config or supervisor scripts
- Give each lane manager distinct session name prefixes to avoid collisions
- Monitor kill-session exit status in the message when debugging survivors
When it happens
Trigger: kill-session completed (with any status) yet has-session still finds the session: something re-creates or respawns it — a respawn hook, another client running new-session for the same name, a supervisor loop, or tmux's remain-on-exit/monitor behavior with external restarts.
Common situations: User shell config or tooling auto-restarts the lane session; two lane managers (or a stray script) targeting the same session name; wrapper commands that re-exec on exit; concurrent stop and re-attach flows racing.
Related errors
- tmux runtime is unavailable: `tmux -V` failed with {}: {}
- tmux has-session for {session} failed with {}: {}
- tmux runtime requires a non-empty command
- lane `{}` was stopped before tmux dry-run start completed
- tmux new-session failed with {status}
AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20).
Data as JSON: /api/errors/49d12c7fbb8a1249.
Report an issue: GitHub.