Hmbown/CodeWhale · error

AutomationEditorConflict

Error message

AutomationEditorConflict

What it means

AutomationEditor::save performs optimistic-concurrency detection: it re-reads the latest stored automation record and compares every field the save request touches (schedule/rrule, cwds, model, status) against the original record the editor loaded. If any differ, someone else modified the automation and it bails with the AutomationEditorConflict message instead of clobbering their changes.

Solutions

  1. Reload the automation in the editor (discard or merge your edits with the latest record) and re-apply changes, then save again.
  2. If the concurrent change is unwanted, revert the record to the original state first, then save.
  3. Retry the save immediately after reload if contention is rare and changes are trivial.
Defensive patterns

Strategy: try-catch

Try / catch

match editor.save() {
    Err(e) if e.to_string().contains("conflict") => { editor.reload_latest(); prompt_user_to_reapply(); }
    other => other?,
}

Prevention

When it happens

Trigger: Calling save with request fields Some(...) where latest.rrule != original.rrule, latest.cwds != original.cwds, ModelChoice::from_record(&latest) != ModelChoice::from_record(original), or latest.status != original.status — i.e. the stored record changed under the editor.

Common situations: Another window/agent edited or paused the same automation while the editor was open; an automated job status transition happened between open and save; a schedule sync tool updated the record.

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@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/13b68670fd6951b8. 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 73e0f67d83)