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

  1. Run the printed-equivalent manually: tmux -S <socket> new-session -d -s <session> '<command>' and read the stderr
  2. Ensure session names are unique per lane (or kill the stale session first)
  3. Verify the socket's parent directory exists and is writable by the current user
  4. 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

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


AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20). Data as JSON: /api/errors/3aa968cafc60f15c. Report an issue: GitHub.