{"record":{"id":"327cac93b0dd1d8f","repo":"Hmbown/CodeWhale","slug":"lane-was-stopped-before-tmux-dry-run-start-co","errorCode":null,"errorMessage":"lane `{}` was stopped before tmux dry-run start completed","messagePattern":"lane `(.+?)` was stopped before tmux dry-run start completed","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/lane/src/runtime.rs","lineNumber":729,"sourceCode":"                \"workflow\": record.workflow,\n                \"fleet\": record.fleet,\n                \"issue\": record.issue,\n                \"dry_run\": dry_run,\n            }),\n        )?;\n\n        if dry_run {\n            append_log_event(\n                &record.log_path,\n                serde_json::json!({\n                    \"type\": \"lane_log\",\n                    \"message\": \"tmux dry-run: session recorded without spawning process\",\n                    \"command\": spec.command,\n                    \"cwd\": cwd.as_ref().map(|p| p.display().to_string()),\n                }),\n            )?;\n            if !registry.mark_running_if_pending(record)? {\n                bail!(\n                    \"lane `{}` was stopped before tmux dry-run start completed\",\n                    record.id\n                );\n            }\n            return Ok(());\n        }\n\n        let log_proxy = spec\n            .log_proxy\n            .as_deref()\n            .context(\"tmux runtime requires a lane log proxy executable\")?;\n\n        // Detached session: child output remains an operator journal only.\n        // Terminal control state goes through a separate bounded, atomically\n        // renamed receipt so child stdout cannot forge Lane completion.\n        let receipt_path = lane_exit_receipt_path(&record.log_path);\n        let receipt_tmp_path = lane_exit_receipt_tmp_path(&record.log_path);\n        let environment_path = lane_environment_path(&record.log_path);","sourceCodeStart":711,"sourceCodeEnd":747,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/lane/src/runtime.rs#L711-L747","documentation":"During a tmux dry-run start (the `CODEWHALE_LANE_TMUX_DRY_RUN` test hook), the runtime records the session without spawning a process and then atomically transitions the lane record to Running via `mark_running_if_pending`. If the pending→running transition fails, the lane was concurrently stopped (or is otherwise no longer pending), and the runtime bails rather than overwriting that stop. This protects the invariant that a stop wins over an in-flight start.","triggerScenarios":"Calling `start` with the dry-run env var set while another thread/process stops the lane between the pending record creation and the `mark_running_if_pending` call — a genuine race — or a corrupted record whose status is not Pending at that point.","commonSituations":"Test/CI harnesses driving dry-run starts concurrently with stop calls; a user issuing `lane stop` while `lane start` is in flight; duplicate start requests for the same lane id where one path already stopped it.","solutions":["Retry the start once the concurrent stop has completed — the lane state is consistent, the start just lost the race.","Serialize start/stop for a given lane (per-lane lock or queue) in your orchestration layer so starts and stops cannot interleave.","Check the lane record's status and log to confirm who stopped it; do not force the record back to Running.","If seen without any concurrent stop, inspect the registry record for corruption — status should have been Pending."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":["Serialize start/stop operations per lane id.","Avoid issuing stop and start concurrently for the same lane in scripts/tests.","Check the lane log to confirm the concurrent stop before retrying."],"tags":["race-condition","lifecycle","tmux"],"backgroundTag":"invalid-state-transition","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}