Hmbown/CodeWhale · error

Invalid coordination ledger

Error message

Invalid coordination ledger: {error}

What it means

After deserializing a persisted sub-agent state snapshot, the coordination ledger inside it is validated with validate_replay() to ensure the recorded events form a consistent, replayable history. If validation fails, the snapshot's coordination data is corrupt or internally inconsistent, so loading is aborted with the validator's error attached.

Solutions

  1. Restore the state file from backup (or let Codewhale rebuild it by removing the corrupt state under state_root).
  2. Read the embedded {error} detail to see which ledger invariant failed; if a single entry is corrupt, that snapshot cannot be partially loaded.
  3. Re-run the workflow that produced the snapshot; live agents will be re-spawned.
  4. Check disk health if corruption recurs across snapshots.

Example fix

// before: loading a corrupt snapshot
let state = load_subagent_state(path)?;
// after: fall back to a fresh session when the ledger is unrecoverable
let state = match load_subagent_state(path) {
    Ok(s) => s,
    Err(e) if e.to_string().contains("Invalid coordination ledger") => fresh_state(),
    Err(e) => return Err(e),
};
Defensive patterns

Strategy: fallback

Validate before calling

fn ledger_valid(raw: &str) -> bool {
    serde_json::from_str::<PersistedSubAgentState>(raw).ok()
        .map(|s| s.coordination.validate_replay().is_ok())
        .unwrap_or(false)
}

Try / catch

let state = match load_subagent_state(path) {
    Ok(s) => s,
    Err(e) if e.to_string().contains("Invalid coordination ledger") => {
        warn!("corrupt ledger, rebuilding");
        backup_and_rebuild(path)
    }
    Err(e) => return Err(e),
};

Prevention

When it happens

Trigger: Restoring sub-agent state from a state file whose coordination entries are missing events, out of order, reference unknown agents, or were truncated by a crash mid-write.

Common situations: Power loss or kill -9 during a state persist; manual edits to the state JSON; copying an inconsistent state file between machines; disk corruption.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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

Appendix: source

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

                legacy
            } else {
                return Ok(());
            }
        };

        let raw = read_subagent_state_file(&self.state_root, &path)?;
        let state = serde_json::from_str::<PersistedSubAgentState>(&raw)?;
        if state.schema_version != SUBAGENT_STATE_SCHEMA_VERSION {
            return Err(anyhow!(
                "Unsupported sub-agent state schema {}",
                state.schema_version
            ));
        }

        let mut coordination = state.coordination;
        coordination
            .validate_replay()
            .map_err(|error| anyhow!("Invalid coordination ledger: {error}"))?;
        self.agents.clear();
        self.worker_records.clear();
        self.persist_sequence.store(
            state.snapshot_sequence,
            std::sync::atomic::Ordering::Relaxed,
        );
        self.coordination = coordination;
        self.resume_targets = state.resume_targets;
        for persisted in state.agents {
            let nickname = persisted
                .nickname
                .filter(|name| generated_whale_name_base(&persisted.id, name).is_none());
            let mut status = persisted.status;
            if matches!(status, SubAgentStatus::Running) {
                status = SubAgentStatus::Interrupted(SUBAGENT_RESTART_REASON.to_string());
            }

            let started_at = instant_from_duration(Duration::from_millis(persisted.duration_ms));

View on GitHub (pinned to 73e0f67d83)