Hmbown/CodeWhale · error · anyhow::Error

for

Error message

{COORDINATION_SAME_PROCESS_HANDOVER} for {}: {error}

What it means

Delegated coordination for a state root is guarded by a cross-process lock file. When acquiring it fails, the code reads the lock file to learn the holder's PID; if that PID is this very process, the conflict is internal (a same-process handover deadlock/misordering) and this distinct error is thrown instead of blaming another Codewhale instance.

Solutions

  1. Check for re-entrant acquisition of the same coordination lock within this process and serialize those paths
  2. Delete the stale lock file under the state root if no coordination is actually active, then retry
  3. Investigate why the inner acquisition failed — the wrapped {error} names it (e.g. lock timeout or flock failure)
  4. Restart the process to clear in-memory lock state

Example fix

// before: same process re-acquires the lock it already holds
acquire_coordination_lock(&lock_path).await?;
// after: skip if this process already holds it
if !is_held_by_current_process(&lock_path) {
    acquire_coordination_lock(&lock_path).await?;
}
Defensive patterns

Strategy: retry

Validate before calling

let holder = std::fs::read_to_string(&lock_path).ok()
    .and_then(|c| c.trim().parse::<u32>().ok());
if holder == Some(std::process::id()) {
    // already held by this process: skip acquisition or reuse the existing guard
}

Type guard

fn lock_held_by_current_process(lock_path: &Path) -> bool {
    std::fs::read_to_string(lock_path).ok()
        .and_then(|c| c.trim().parse::<u32>().ok())
        == Some(std::process::id())
}

Try / catch

match try_acquire_coordination(&lock_path) {
    Ok(guard) => guard,
    Err(e) if lock_held_by_current_process(&lock_path) => reuse_in_process_guard(),
    Err(e) => return Err(anyhow!("coordination lock unavailable: {e}")),
}

Prevention

When it happens

Trigger: Taking delegated coordination for state_root fails, and the lock file's stored PID parses to the current process ID — i.e. this process already holds (or stale-held) the coordination lock.

Common situations: Nested or re-entrant coordination acquisition in one process; a stale lock file left by a previous crashed instance that coincidentally reuses the current PID; spawning parallel coordination threads in the same process without releasing the lock.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15). Data as JSON: /api/errors/f72cf2c1e9f57129. Report an issue: GitHub.

Appendix: source

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

                    let _ = release_rx.recv();
                }
                Err(error) => {
                    let _ = ready_tx.send(Err(error.to_string()));
                }
            }
        });
        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}",

View on GitHub (pinned to 433685b202)