{"record":{"id":"fdeab4429898755e","repo":"Hmbown/CodeWhale","slug":"tmux-runtime-requires-a-non-empty-command","errorCode":null,"errorMessage":"tmux runtime requires a non-empty command","messagePattern":"tmux runtime requires a non-empty command","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/lane/src/runtime.rs","lineNumber":674,"sourceCode":"}\n\n/// Durable local tmux sessions + attach + stream-json log file.\n#[derive(Debug, Default)]\npub struct TmuxRuntime;\n\nimpl RuntimeBackend for TmuxRuntime {\n    fn kind(&self) -> RuntimeBackendKind {\n        RuntimeBackendKind::Tmux\n    }\n\n    fn start(\n        &self,\n        registry: &LaneRegistry,\n        record: &mut LaneRecord,\n        spec: &LaneStartSpec,\n    ) -> Result<()> {\n        if spec.command.is_empty() {\n            bail!(\"tmux runtime requires a non-empty command\");\n        }\n        // Dry-run is an explicit test hook only. A missing/broken tmux binary\n        // must fail closed rather than persisting a fictional Running Lane.\n        let dry_run = std::env::var_os(\"CODEWHALE_LANE_TMUX_DRY_RUN\").is_some();\n        if !dry_run && let Err(error) = ensure_tmux_available() {\n            append_log_event(\n                &record.log_path,\n                serde_json::json!({\n                    \"type\": \"lane_failed\",\n                    \"lane_id\": record.id,\n                    \"runtime\": \"tmux\",\n                    \"error\": error.to_string(),\n                }),\n            )?;\n            let _ = registry.mark_terminal_if_active(record, LaneStatus::Failed)?;\n            return Err(error);\n        }\n","sourceCodeStart":656,"sourceCodeEnd":692,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/0c42157ee52f9d55af2b506d71b46249910f77d3/crates/lane/src/runtime.rs#L656-L692","documentation":"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.","triggerScenarios":"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.","commonSituations":"Config with an empty/whitespace command field (\"command\": \"\"); CLI flag provided without a value; programmatically building commands from filtered lists that end up empty.","solutions":["Provide a real command (e.g. [\"$SHELL\"] or [\"bash\"]) in the start spec","Validate at your own boundary: reject blank command strings before they become specs","If the command came from config, fix the config entry and retry"],"exampleFix":"// before\nlet spec = LaneStartSpec { command: cmdline.split_whitespace().collect(), .. }; // blank input -> []\n\n// after\nlet command: Vec<String> = cmdline.split_whitespace().map(String::from).collect();\nif command.is_empty() {\n    anyhow::bail!(\"lane command is empty\");\n}\nlet spec = LaneStartSpec { command, .. };","handlingStrategy":"validation","validationCode":"anyhow::ensure!(!spec.command.is_empty(), \"lane command must not be empty\");","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Reject blank command strings when parsing config or CLI input","Default to a shell ([$SHELL] or [\"bash\"]) when a lane's purpose is interactive"],"tags":["rust","lane","tmux","validation","empty-argument"],"backgroundTag":"empty-required-field","analyzedSha":"0c42157ee52f9d55af2b506d71b46249910f77d3","analyzedAt":"2026-08-20T21:50:45.477Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}