Hmbown/CodeWhale · error

{}

Error message

{}

What it means

Thrown in `AutomationEditor::save` when a concurrent modification is detected: the automation record was changed by someone else since the editor loaded it, and the pending update request touches those fields (name/prompt, schedule, rrule, cwds, model, or status). The message is the localized `AutomationEditorConflict` string. `save` compares `latest` against `original` field-by-field only for fields the request will overwrite, then aborts rather than silently clobbering.

Solutions

  1. Reload the editor with the latest record, re-apply your edits, and save again
  2. Save promptly after opening the editor to shrink the conflict window
  3. Coordinate edits: check whether another session/tool is managing this automation
  4. If the conflict is only in fields you did not intend to change, narrow the update request to the fields you actually edited

Example fix

null
Defensive patterns

Strategy: retry

Validate before calling

let latest = manager.get_automation(&original.id)?;
let conflicted = (request.name.is_some() && latest.name != original.name)
    || (request.status.is_some() && latest.status != original.status);
if conflicted { /* reload before saving */ }

Try / catch

match save_result {
    Err(e) if e.to_string().contains("conflict") || e.to_string().contains("changed") => {
        // reload latest record, merge/re-apply edits, retry save once
    }
    other => other?,
}

Prevention

When it happens

Trigger: Calling `save` on an existing automation when any overwritten field differs between the DB's `latest` record and the editor's `original` snapshot: a rename/edit elsewhere, a schedule change, cwd list change, model switch, or status toggle (e.g. pause from another session) happened between open and save.

Common situations: Two TUI sessions editing the same automation; a scheduler or CLI pausing/renaming the automation while the editor dialog is open; long-lived editor left open while automation state changed underneath.

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


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

Appendix: source

Thrown at crates/tui/src/tui/views/automations/editor.rs:684

                cwds: workspace_changed.then_some(cwds),
                model: (choice != ModelChoice::from_record(original))
                    .then(|| choice.model.clone().unwrap_or_default()),
                model_provider: (choice != ModelChoice::from_record(original))
                    .then(|| choice.provider.clone().unwrap_or_default()),
                model_provider_id: (choice != ModelChoice::from_record(original))
                    .then(|| choice.provider_id.clone().unwrap_or_default()),
                status: (status != original.status).then_some(status),
                ..Default::default()
            };
            if (request.name.is_some() && latest.name != original.name)
                || (request.prompt.is_some() && latest.prompt != original.prompt)
                || (request.rrule.is_some() && latest.rrule != original.rrule)
                || (request.cwds.is_some() && latest.cwds != original.cwds)
                || (request.model.is_some()
                    && ModelChoice::from_record(&latest) != ModelChoice::from_record(original))
                || (request.status.is_some() && latest.status != original.status)
            {
                anyhow::bail!("{}", tr(self.locale, MessageId::AutomationEditorConflict));
            }
            manager.update_automation(&original.id, request)
        } else {
            manager.create_automation(CreateAutomationRequest {
                name: self.name.value.clone(),
                prompt: self.prompt.value.clone(),
                rrule,
                cwds,
                model: choice.model,
                model_provider: choice.provider,
                model_provider_id: choice.provider_id,
                status: Some(status),
                mode: None,
                allow_shell: None,
                trust_mode: None,
                auto_approve: None,
                delivery_mode: None,
            })

View on GitHub (pinned to 433685b202)