Hmbown/CodeWhale · error · anyhow::Error

tmux runtime requires a non-empty command

Error message

tmux runtime requires a non-empty command

What it means

TmuxRuntime::start rejects a LaneStartSpec whose command vector is empty before touching the registry, worktree, or tmux. An empty command has no argv[0] to hand to tmux new-session, so this is input validation at the API boundary — the lane is never created or transitioned.

Source

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

}

/// Durable local tmux sessions + attach + stream-json log file.
#[derive(Debug, Default)]
pub struct TmuxRuntime;

impl RuntimeBackend for TmuxRuntime {
    fn kind(&self) -> RuntimeBackendKind {
        RuntimeBackendKind::Tmux
    }

    fn start(
        &self,
        registry: &LaneRegistry,
        record: &mut LaneRecord,
        spec: &LaneStartSpec,
    ) -> Result<()> {
        if spec.command.is_empty() {
            bail!("tmux runtime requires a non-empty command");
        }
        // Dry-run is an explicit test hook only. A missing/broken tmux binary
        // must fail closed rather than persisting a fictional Running Lane.
        let dry_run = std::env::var_os("CODEWHALE_LANE_TMUX_DRY_RUN").is_some();
        if !dry_run && let Err(error) = ensure_tmux_available() {
            append_log_event(
                &record.log_path,
                serde_json::json!({
                    "type": "lane_failed",
                    "lane_id": record.id,
                    "runtime": "tmux",
                    "error": error.to_string(),
                }),
            )?;
            let _ = registry.mark_terminal_if_active(record, LaneStatus::Failed)?;
            return Err(error);
        }

View on GitHub (pinned to 0c42157ee5)

Solutions

  1. Provide a real command (e.g. ["$SHELL"] or ["bash"]) in the start spec
  2. Validate at your own boundary: reject blank command strings before they become specs
  3. If the command came from config, fix the config entry and retry

Example fix

// before
let spec = LaneStartSpec { command: cmdline.split_whitespace().collect(), .. }; // blank input -> []

// after
let command: Vec<String> = cmdline.split_whitespace().map(String::from).collect();
if command.is_empty() {
    anyhow::bail!("lane command is empty");
}
let spec = LaneStartSpec { command, .. };
Defensive patterns

Strategy: validation

Validate before calling

anyhow::ensure!(!spec.command.is_empty(), "lane command must not be empty");

Prevention

When it happens

Trigger: Calling lane start with backend "tmux" and spec.command = []. Typical when command is built by splitting a user string that was blank, or by an option parser defaulting to an empty vec.

Common situations: Config with an empty/whitespace command field ("command": ""); CLI flag provided without a value; programmatically building commands from filtered lists that end up empty.

Related errors


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