Hmbown/CodeWhale · error
A cancelled Operation cannot be edited.
Error message
A cancelled Operation cannot be edited.
What it means
apply_operate_patch refuses to mutate an Operation whose status is Cancelled. Cancellation is terminal: once an Operation is cancelled its recorded fields are frozen so history stays consistent, and any patch (direction, leadPlan, etc.) is rejected.
Solutions
- Check `op.status` before editing and skip cancelled operations
- Create a new Operation instead of editing the cancelled one
- If the operation should not have been cancelled, restart it as a new operation rather than un-cancelling
Example fix
// before
apply_operate_patch(&mut op, &patch)?;
// after
if op.status != OperateStatus::Cancelled {
apply_operate_patch(&mut op, &patch)?;
} Defensive patterns
Strategy: validation
Validate before calling
fn editable(op: &Operation) -> bool { op.status != OperateStatus::Cancelled } Try / catch
match apply_operate_patch(&mut op, &patch) { Err(e) if e.to_string().contains("cannot be edited") => eprintln!("operation was cancelled; create a new one"), other => other?, } Prevention
- Filter cancelled operations out of bulk-edit lists
- Check status in the UI before enabling edit controls
- Treat cancellation as terminal in automation flows
When it happens
Trigger: Calling apply_operate_patch (or an edit API that routes to it) with a JSON patch targeting an Operation with status == Cancelled.
Common situations: UI or automation still holds a stale handle to an operation the user cancelled; a retry/update job firing after cancellation; bulk edits iterating over operations including cancelled ones.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- {}: {detail}
- DSH is already connected; use
- DSH is not connected; nothing to
- DSH is not connected; run
- element does not belong to the bound application —…
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/1f6e834bdc900fb1.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/operate.rs:1091
Ok(())
})?;
if let Some(op) = attached {
return Ok(op);
}
}
start_operation(
store,
workspace,
direction,
burn_usd_per_hour,
credentials_present,
lead_model,
)
}
pub fn apply_operate_patch(op: &mut Operation, patch: &serde_json::Value) -> Result<()> {
if op.status == OperateStatus::Cancelled {
anyhow::bail!("A cancelled Operation cannot be edited.");
}
if let Some(direction) = patch.get("direction") {
let next = normalize_direction(direction.as_str().map(str::to_string).unwrap_or_default());
if patch.get("leadPlan").is_none() && next != op.direction {
// A changed direction supersedes the recorded lead plan: workers
// must stop executing slices derived from the old direction. The
// operation idles `awaiting_lead_plan` until the lead re-plans
// (same patch may instead carry an explicit replacement plan).
op.lead_plan = None;
}
op.direction = next;
}
if patch.get("burnRate").is_some() {
op.burn_rate = parse_burn_rate(patch.get("burnRate"))?;
}
if let Some(plan) = patch.get("leadPlan") {
op.lead_plan = if plan.is_null() {
NoneView on GitHub (pinned to 73e0f67d83)