Hmbown/CodeWhale · error

another Codewhale process

Error message

another Codewhale process{} owns delegated coordination for {}: {error}

What it means

Delegated sub-agent coordination state is guarded by a cross-process lock file under state_root. When lock acquisition fails and the holder PID recorded in the lock file is a different process, this error reports which process (by PID) owns the coordination, so the caller knows the operation cannot proceed until that process exits or releases.

Solutions

  1. Identify and stop the other Codewhale process listed in the message (kill <pid>) or wait for it to finish.
  2. Use a different state_root / workspace so the two processes do not contend for the same delegated coordination.
  3. If the PID no longer exists (crashed holder), verify with ps -p <pid> and remove the stale lock file.
  4. Retry the operation once the other process has released coordination.

Example fix

// before: blind retry against a held lock
let result = spawn_delegated(state_root);
// after: check holder before attempting
let holder = std::fs::read_to_string(state_root.join("coordination.lock")).ok();
if holder_is_live_other_process(&holder) { return Err(/* surface holder pid, don't retry */); }
let result = spawn_delegated(state_root);
Defensive patterns

Strategy: retry

Validate before calling

fn other_process_holds(state_root: &Path) -> Option<u32> {
    std::fs::read_to_string(state_root.join("coordination.lock")).ok()
        .and_then(|c| c.trim().parse::<u32>().ok())
        .filter(|pid| *pid != std::process::id())
}

Type guard

fn holder_is_external(state_root: &Path) -> bool {
    other_process_holds(state_root).is_some()
}

Try / catch

match acquire_delegated_coordination(state_root) {
    Err(e) if e.to_string().contains("another Codewhale process") => {
        eprintln!("coordination held elsewhere; retry after it exits");
        backoff_retry(state_root, 3);
    }
    r => r?,
}

Prevention

When it happens

Trigger: Starting a delegated sub-agent operation whose state_root coordination lock file records a holder PID different from std::process::id(), while the lock acquisition attempt returned Err(error) (timeout or refusal).

Common situations: Two Codewhale instances (or a TUI and a CLI) sharing a workspace state_root; a crashed predecessor left a valid lock file; parallel agent runs in separate terminals on the same project.

Related errors


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

Appendix: source

Thrown at crates/tui/src/tools/subagent/mod.rs:3461

            }
        });
        match ready_rx.recv_timeout(Duration::from_secs(5)) {
            Ok(Ok(())) => Ok(Self {
                release: Some(release_tx),
                thread: Some(thread),
            }),
            Ok(Err(error)) => {
                let _ = thread.join();
                let holder_pid = std::fs::read_to_string(&lock_path)
                    .ok()
                    .and_then(|contents| contents.trim().parse::<u32>().ok());
                if holder_pid == Some(std::process::id()) {
                    Err(anyhow!(
                        "{COORDINATION_SAME_PROCESS_HANDOVER} for {}: {error}",
                        state_root.display()
                    ))
                } else {
                    Err(anyhow!(
                        "another Codewhale process{} owns delegated coordination for {}: {error}",
                        holder_pid
                            .map(|pid| format!(" (pid {pid})"))
                            .unwrap_or_default(),
                        state_root.display()
                    ))
                }
            }
            Err(error) => {
                drop(release_tx);
                let _ = thread.join();
                Err(anyhow!(
                    "{COORDINATION_LOCK_TIMEOUT_MARKER} for {}: {error}",
                    state_root.display()
                ))
            }
        }
    }

View on GitHub (pinned to 73e0f67d83)