Hmbown/CodeWhale · error

lane ` ` was stopped before tmux launch

Error message

lane `{}` was stopped before tmux launch

What it means

This is the lane-stopped-during-start guard on the real (non-dry-run) tmux launch path. If the lane's stop flag/record indicates the lane was stopped while the tmux launch was being prepared, the runtime cleans up the environment file and worktree, marks the record stopped, and bails instead of starting a lane someone asked to stop. Like 614 it enforces 'stop wins over in-flight start'.

Solutions

  1. Confirm the lane's current state with stop/log inspection, then start it again if a running lane is actually wanted.
  2. Serialize start/stop per lane id in the calling layer to avoid interleaving.
  3. If the stop was unintended, restart the lane — the record was left cleanly stopped with worktree cleaned.
  4. If triggered with no concurrent stop, check the record's stopped_at/log for who set the stop and whether registry state is corrupt.
Defensive patterns

Strategy: try-catch

Prevention

When it happens

Trigger: Calling `start` on a lane whose record gets stopped between the start entry point and the tmux spawn — a concurrent `stop`/`reconcile` on the same lane id, or a pre-existing stopped_at set on the record that start detected late.

Common situations: A user stops a slow-starting lane (long worktree setup) while start is in flight; an orchestrator's timeout kills the lane mid-start; duplicate start invocations where a first one already stopped the record.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/c75c0e2bccd4c4db. Report an issue: GitHub.

Appendix: source

Thrown at crates/lane/src/runtime.rs:802

                }
                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)?;
                bail!("lane `{}` was stopped before tmux launch", record.id);
            }
            Err(error) => {
                if let Some(path) = environment_path.as_deref() {
                    let _ = remove_file_if_present(path);
                }
                if !spawned.get() || rolled_back.get() {
                    let _ = registry.mark_terminal_if_active(record, LaneStatus::Failed)?;
                    let mut failed_record = proposed_record;
                    failed_record.stopped_at = record.stopped_at.clone();
                    self.cleanup_worktree(&failed_record)?;
                }
                return Err(error);
            }
        }
        Ok(())
    }

    fn attach_command(&self, record: &LaneRecord) -> Option<String> {

View on GitHub (pinned to 73e0f67d83)