Hmbown/CodeWhale · error
attempt receipt identity does not match its terminal event
Error message
attempt receipt identity does not match its terminal event
What it means
FleetLedger::finalize_task_attempt_if_leased binds the receipt to the terminal event it accompanies. The guard at crates/tui/src/fleet/ledger.rs:979 rejects the call when the receipt's run_id, task_id, or worker_id does not match the run/task/worker arguments of the call. A mismatched receipt would attach evidence from one attempt (or another task entirely) to a different attempt's terminal record.
Solutions
- Rebuild the FleetReceipt from the current attempt's run_id/task_id/worker_id before finalizing.
- Check the receipt fields against the call arguments and regenerate it when they diverge.
- Key receipt storage by (run_id, task_id, worker_id) so the wrong receipt cannot be fetched.
Example fix
// before let receipt = old_receipt; // built for another attempt ledger.finalize_task_attempt_if_leased(&run_id, &worker_id, &task_id, attempts, &ts, payload, status, receipt)?; // after assert_eq!(old_receipt.run_id, *run_id); assert_eq!(old_receipt.task_id, task_id); assert_eq!(old_receipt.worker_id, worker_id); ledger.finalize_task_attempt_if_leased(&run_id, &worker_id, &task_id, attempts, &ts, payload, status, old_receipt)?;
Defensive patterns
Strategy: validation
Validate before calling
assert_eq!(receipt.run_id, *run_id); assert_eq!(receipt.task_id, task_id); assert_eq!(receipt.worker_id, worker_id);
Try / catch
if let Err(e) = finalize_result {
if e.to_string().contains("receipt identity does not match") { /* rebuild receipt for this attempt */ }
} Prevention
- Store receipts keyed by (run_id, task_id, worker_id) so lookups cannot cross attempts.
- Rebuild receipts at finalize time from current identifiers instead of caching them.
- Never copy a receipt across loop iterations that rebind task/worker variables.
When it happens
Trigger: Calling finalize_task_attempt_if_leased with a FleetReceipt built for a different run, task, or worker — e.g. a cached receipt from a previous attempt, a receipt copied across workers, or arguments swapped at the call site.
Common situations: Reusing a stored receipt after the task was restarted on another worker; aggregating receipts in a map keyed by the wrong id; a driver loop that holds a stale receipt while task/worker identifiers were rebound.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- attempt finalization requires a terminal worker event
- attempt finalization status must be terminal
- attempt receipt generation does not match its lease
- conditional progress append does not accept terminal worker…
- conditional terminal append requires a terminal worker event
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/aa5758960f596179.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/fleet/ledger.rs:979
FleetWorkerEventPayload::Completed { .. }
| FleetWorkerEventPayload::Failed { .. }
| FleetWorkerEventPayload::Cancelled { .. }
) {
bail!("attempt finalization requires a terminal worker event");
}
if final_status.is_some_and(|status| {
!matches!(
status,
FleetTaskLedgerStatus::Completed
| FleetTaskLedgerStatus::Failed
| FleetTaskLedgerStatus::Cancelled
)
}) {
bail!("attempt finalization status must be terminal");
}
if receipt.run_id != *run_id || receipt.task_id != task_id || receipt.worker_id != worker_id
{
bail!("attempt receipt identity does not match its terminal event");
}
if receipt
.attempt
.is_some_and(|attempt| attempt != expected_attempts)
{
bail!("attempt receipt generation does not match its lease");
}
self.with_write_lock(|| {
let state = self.rebuild_state_unlocked()?;
let key = task_key(&run_id.0, task_id);
let Some(task) = state.tasks.get(&key) else {
return Ok(None);
};
if task.status != FleetTaskLedgerStatus::Leased
|| task.leased_to.as_deref() != Some(worker_id)
|| task.entry.attempts != expected_attempts
{
return Ok(None);View on GitHub (pinned to 73e0f67d83)