{"record":{"id":"6b3280282c20fb3e","repo":"warpdotdev/warp","slug":"cannot-delete-schedule-with-pending-changes","errorCode":null,"errorMessage":"Cannot delete schedule with pending changes","messagePattern":"Cannot delete schedule with pending changes","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"app/src/ai/ambient_agents/scheduled.rs","lineNumber":373,"sourceCode":"        schedule_id: SyncId,\n        ctx: &mut ModelContext<Self>,\n    ) -> impl Future<Output = anyhow::Result<()>> + Send + 'static + use<> {\n        let id_and_type = CloudObjectTypeAndId::GenericStringObject {\n            object_type: GenericStringObjectFormat::Json(JsonObjectType::ScheduledAmbientAgent),\n            id: schedule_id,\n        };\n\n        let (tx, rx) = oneshot::channel();\n\n        match CloudModel::as_ref(ctx).get_by_uid(&schedule_id.uid()) {\n            None => {\n                let _ = tx.send(Err(anyhow::anyhow!(\"Schedule {schedule_id} not found\")));\n            }\n            Some(schedule) => {\n                if schedule.metadata().has_pending_online_only_change()\n                    || schedule.metadata().pending_changes_statuses.pending_delete\n                {\n                    let _ = tx.send(Err(anyhow::anyhow!(\n                        \"Cannot delete schedule with pending changes\"\n                    )));\n                } else {\n                    self.pending_deletes.insert(schedule_id, tx);\n                    UpdateManager::handle(ctx).update(ctx, |update_manager, ctx| {\n                        update_manager.delete_object_by_user(id_and_type, ctx);\n                    });\n                }\n            }\n        }\n\n        async move {\n            rx.await\n                .map_err(|e| anyhow::anyhow!(\"Failed to delete schedule: {}\", e))?\n        }\n    }\n}\n","sourceCodeStart":355,"sourceCodeEnd":391,"githubUrl":"https://github.com/warpdotdev/warp/blob/e72fd7aacbbb2236d9b3be2aad7e7178fe94b4bc/app/src/ai/ambient_agents/scheduled.rs#L355-L391","documentation":"delete_schedule refuses to enqueue a deletion when the object's metadata reports has_pending_online_only_change() or pending_changes_statuses.pending_delete. This guard prevents issuing a delete that conflicts with unsynced online-only edits or a delete that is already queued for sync.","triggerScenarios":"Calling delete_schedule on a schedule where schedule.metadata().has_pending_online_only_change() is true (an online-only edit not yet acknowledged by the server) or pending_changes_statuses.pending_delete is true (a delete already in flight).","commonSituations":"User clicks delete twice in quick succession; deleting immediately after editing a schedule while the edit has not synced; an offline period that left pending changes stranded; flaky network that keeps changes pending.","solutions":["Wait for pending changes to flush (poll metadata().pending_changes_statuses until clear) and retry the delete","If a delete is already pending, do not enqueue another - await or surface the existing one's result","Restore connectivity so online-only changes can sync, then retry","If changes stay pending, restart the client to force a cloud reconciliation, then retry"],"exampleFix":"// before\nmanager.delete_schedule(schedule_id, ctx).await?;\n\n// after\nif let Some(obj) = CloudModel::as_ref(ctx).get_by_uid(&schedule_id.uid()) {\n    let m = obj.metadata();\n    if m.has_pending_online_only_change() || m.pending_changes_statuses.pending_delete {\n        // let sync settle first; surface 'deleting...' state to the user\n        return wait_and_retry_delete(schedule_id).await;\n    }\n}\nmanager.delete_schedule(schedule_id, ctx).await?;","handlingStrategy":"validation","validationCode":"if let Some(obj) = CloudModel::as_ref(ctx).get_by_uid(&schedule_id.uid()) {\n    let m = obj.metadata();\n    if m.has_pending_online_only_change() || m.pending_changes_statuses.pending_delete {\n        // block delete in UI; wait for sync to settle\n    }\n}","typeGuard":"fn deletable(obj: &CloudScheduledAmbientAgent) -> bool {\n    let m = obj.metadata();\n    !m.has_pending_online_only_change() && !m.pending_changes_statuses.pending_delete\n}","tryCatchPattern":"match manager.delete_schedule(id, ctx).await {\n    Err(e) if e.to_string().contains(\"pending changes\") => {\n        wait_for_sync(ctx).await; // then retry once\n        manager.delete_schedule(id, ctx).await\n    }\n    other => other,\n}","preventionTips":["Surface pending-sync state in the UI so users understand why delete is blocked","Debounce or confirm double-delete clicks while a delete is pending","Never enqueue mutations on objects flagged with pending online-only changes"],"tags":["rust","warp","cloud-sync","scheduling","conflict-prevention"],"backgroundTag":null,"analyzedSha":"e72fd7aacbbb2236d9b3be2aad7e7178fe94b4bc","analyzedAt":"2026-08-16T08:27:25.381Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}