zeroclaw-labs/zeroclaw · warning · anyhow::Error

cannot record checkpoint approval vote for run {run_id}: its

Error message

cannot record checkpoint approval vote for run {run_id}: its parked snapshot is not yet durably persisted (retrying)

What it means

While recording a checkpoint approval vote, the broker checks engine.is_park_persist_pending(run_id). If the run's parked snapshot has not yet been durably written, the vote is refused: a vote recorded now could durably outlive a park that is lost on restart (an orphaned gate_vote row for a nonexistent run). This is a deliberate fail-closed, transient condition — it clears once the park flush completes.

Source

Thrown at crates/zeroclaw-runtime/src/sop/approval/broker.rs:400

        };

        if matches!(decision, ApprovalDecision::Deny { .. }) {
            return Ok(None);
        }
        let Some((decision_label, decision_identity)) = checkpoint_decision_identity(decision)
        else {
            return Ok(None);
        };
        let checkpoint_revision = engine
            .get_run(run_id)
            .map(|run| run.revision)
            .unwrap_or_default();
        let need = policy.1.quorum.max(1) as usize;
        if need <= 1 {
            return Ok(None);
        }
        if engine.is_park_persist_pending(run_id) {
            anyhow::bail!(
                "cannot record checkpoint approval vote for run {run_id}: its parked snapshot is not yet durably persisted (retrying)"
            );
        }
        engine.record_checkpoint_gate_vote(
            run_id,
            step,
            &policy.0,
            checkpoint_revision,
            decision_label,
            &decision_identity,
            principal,
        )?;
        let have = self.count_qualified_voters(
            engine,
            run_id,
            step,
            &policy.0,
            policy.1.required_group.as_deref().filter(|g| !g.is_empty()),

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Retry the vote after a short delay (with bounded backoff) — the error is explicitly retryable and self-clears.
  2. If it persists, check engine logs for park-persist failures (disk full, DB errors) and fix the underlying IO problem.
  3. In automation, treat this message as a 'try again' signal, not a failure — do not re-create the run.
  4. Verify the runs's park state settled (run shows parked durably) before firing the second and later votes.

Example fix

// before
broker.authorize_checkpoint(run_id, step, decision).await?; // fails on first retry-window hit

// after
let mut backoff = Duration::from_millis(200);
loop {
    match broker.authorize_checkpoint(run_id, step, decision.clone()).await {
        Ok(out) => break out,
        Err(e) if e.to_string().contains("not yet durably persisted") && backoff <= Duration::from_secs(10) => {
            tokio::time::sleep(backoff).await;
            backoff *= 2;
        }
        Err(e) => return Err(e),
    }
}
Defensive patterns

Strategy: retry

Validate before calling

if engine.is_park_persist_pending(run_id) {
    // wait or reschedule; do not call authorize_checkpoint yet
    return ScheduleRetry::after(Duration::from_millis(250));
}

Try / catch

let mut delay = Duration::from_millis(200);
loop {
    match broker.authorize_checkpoint(run_id, step, vote.clone()).await {
        Ok(out) => break out,
        Err(e) if e.to_string().contains("not yet durably persisted") && delay <= Duration::from_secs(10) => {
            tokio::time::sleep(delay).await;
            delay *= 2;
        }
        Err(e) => return Err(e),
    }
}

Prevention

When it happens

Trigger: authorize_checkpoint (reached via resolve_via_broker) with a quorum policy needing >1 vote, invoked in the window right after the run parks but before its snapshot write reaches durable storage. More likely under slow disks, heavy IO, or immediately-scripted vote sequences.

Common situations: Automated multi-approver scripts that vote in rapid succession after a gate opens; CI pipelines approving a checkpoint within milliseconds of park; slow or saturated storage delaying the park persist; restart-adjacent races in tests.

Related errors


AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23). Data as JSON: /api/errors/080ed40d91712768. Report an issue: GitHub.