Hmbown/CodeWhale · error · anyhow::Error

lane `{}` was stopped before inline start completed

Error message

lane `{}` was stopped before inline start completed

What it means

InlineRuntime::start applies the worktree and appends the lane_started event, then calls registry.mark_running_if_pending(record). A false return means a concurrent stop already moved the lane out of Pending, so the start aborts before spawning the child process — no orphan process is left behind, and the caller gets this explicit race signal.

Source

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

        registry: &LaneRegistry,
        record: &mut LaneRecord,
        spec: &LaneStartSpec,
    ) -> Result<()> {
        if spec.command.is_empty() {
            bail!("inline runtime requires a non-empty command");
        }
        let cwd = apply_worktree(record, spec)?;
        append_log_event(
            &record.log_path,
            serde_json::json!({
                "type": "lane_started",
                "lane_id": record.id,
                "runtime": "inline",
                "command": spec.command,
            }),
        )?;
        if !registry.mark_running_if_pending(record)? {
            bail!(
                "lane `{}` was stopped before inline start completed",
                record.id
            );
        }

        let mut cmd = Command::new(&spec.command[0]);
        if spec.command.len() > 1 {
            cmd.args(&spec.command[1..]);
        }
        if let Some(cwd) = cwd.as_ref() {
            cmd.current_dir(cwd);
        }
        cmd.envs(spec.environment.iter().map(|(key, value)| (key, value)));
        cmd.stdout(Stdio::piped()).stderr(Stdio::piped());
        let mut child = match cmd.spawn() {
            Ok(child) => child,
            Err(err) => {
                append_log_event(

View on GitHub (pinned to 0c42157ee5)

Solutions

  1. Refetch the lane record and treat it as stopped (it is); decide explicitly whether to start again
  2. Await start completion before issuing stop in calling code
  3. Coordinate concurrent lifecycle operations per lane (locks or fences)
Defensive patterns

Strategy: try-catch

Try / catch

match runtime.start(&registry, &mut record, &spec) {
    Ok(()) => { /* child spawned */ }
    Err(err) if err.to_string().contains("stopped before inline start completed") => {
        // Race lost to a concurrent stop; no child was spawned, worktree may remain per caller.
        let fresh = registry.get(&record.id)?;
        assert_eq!(fresh.status, LaneStatus::Stopped);
    }
    Err(err) => return Err(err),
}

Prevention

When it happens

Trigger: An inline lane start racing a concurrent stop on the same lane id: the stop's terminal transition commits between the lane_started log event and the Pending->Running compare-and-set.

Common situations: UIs letting users cancel while a lane is launching; automation that stops on a timeout fired right after start; concurrent managers operating the same lane registry.

Related errors


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