Hmbown/CodeWhale · error · anyhow::Error
tmux new-session failed with {status}
Error message
tmux new-session failed with {status} What it means
Inside the registry's mark_running_if_pending_with start closure, TmuxRuntime runs the assembled `tmux new-session ...` synchronously; a nonzero exit bails with the status. The registry's rollback closure then kills the session (if one materialized), so the lane does not linger in a half-spawned state, and the outer error path marks the record Failed and cleans the worktree.
Source
Thrown at crates/lane/src/runtime.rs:783
);
let mut cmd = tmux_command(&socket);
cmd.args(["new-session", "-d", "-s", &session]);
if let Some(cwd) = cwd.as_ref() {
cmd.arg("-c").arg(cwd);
}
cmd.arg(shell_cmd);
let proposed_record = record.clone();
let spawned = std::cell::Cell::new(false);
let rolled_back = std::cell::Cell::new(false);
match registry.mark_running_if_pending_with(
record,
|| {
let status = cmd
.status()
.with_context(|| format!("spawn tmux session {session}"))?;
if !status.success() {
bail!("tmux new-session failed with {status}");
}
spawned.set(true);
Ok(())
},
|| {
stop_tmux_session(&socket, &session)?;
rolled_back.set(true);
Ok(())
},
) {
Ok(true) => {}
Ok(false) => {
if let Some(path) = environment_path.as_deref() {
remove_file_if_present(path)?;
}
let mut stopped_record = proposed_record;
stopped_record.stopped_at = record.stopped_at.clone();
self.cleanup_worktree(&stopped_record)?;View on GitHub (pinned to 0c42157ee5)
Solutions
- Run the printed-equivalent manually: tmux -S <socket> new-session -d -s <session> '<command>' and read the stderr
- Ensure session names are unique per lane (or kill the stale session first)
- Verify the socket's parent directory exists and is writable by the current user
- Check the command string for quoting/escaping bugs when it was assembled from parts
Example fix
# before
# session name reused across runs
let session = format!("codewhale");
# after
let session = format!("codewhale-{lane_id}");
# and ensure the socket parent exists
fs::create_dir_all(socket.parent().unwrap())?; Defensive patterns
Strategy: retry
Validate before calling
fn tmux_launch_preconditions_met(socket: &Path, session: &str) -> bool {
socket
.parent()
.map(|p| p.exists())
.unwrap_or(false)
&& !session.is_empty()
&& session.chars().all(|c| c.is_ascii_alphanumeric() || c == '-' || c == '_')
} Try / catch
match start_result {
Err(err) if err.to_string().contains("new-session failed") => {
// Inspect manually: tmux -S <socket> new-session -d -s <session> '<cmd>'
// Retry once after clearing a stale same-name session if that was the cause.
}
other => other?,
} Prevention
- Derive session names from lane ids so they cannot collide
- Create the socket parent directory before start and keep it writable
- Assemble commands as argv vectors, not quoted strings, where possible
When it happens
Trigger: tmux new-session exiting nonzero: session name already exists on that socket, socket directory missing or unwritable, an invalid command string passed through the shell wrapper, or tmux server startup failures.
Common situations: Reusing a session name from a previous lane that was not reaped; socket parent directory removed by tmp cleaners; commands with unbalanced quotes built via string concatenation; permissions after a uid change (sudo, container user mismatch).
Related errors
- tmux has-session for {session} failed with {}: {}
- tmux runtime is unavailable: `tmux -V` failed with {}: {}
- tmux session {session} remains active after kill-session ({s
- tmux runtime requires a non-empty command
- lane `{}` was stopped before tmux dry-run start completed
AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20).
Data as JSON: /api/errors/3aa968cafc60f15c.
Report an issue: GitHub.