fix: prevent cascade rollback from restoring deleted session descendants (#1555)

The OpenCode server cascade-deletes all child sessions when a parent
is removed. The client was sending individual DELETE requests for each
descendant, which returned 404 after the parent's cascade removed them.
The 404 triggered rollback in deleteSessionAction, restoring already-
deleted sessions back into the global store.

Changes:
- executeDeleteSession: only send the root session delete; the server
  cascade handles descendants.
- deleteSession / deleteSessionInDirectory: treat 404 in catch as
  success, acting as a safety net for remaining paths (e.g. sidebar
  bulk action bar when parent and child are both selected).
This commit is contained in:
Tom
2026-06-12 22:54:39 +03:00
committed by GitHub
parent 201c7014d7
commit a0597b1065
2 changed files with 21 additions and 10 deletions
@@ -214,16 +214,18 @@ export const useSessionActions = (args: Args) => {
const ids = [session.id, ...descendantIds];
if (shouldHardDelete) {
const { deletedIds, failedIds } = await args.deleteSessions(ids);
if (deletedIds.length > 0) {
toast.success(deletedIds.length === 1
? t('sessions.sidebar.bulkActions.deletedSingle', { count: deletedIds.length })
: t('sessions.sidebar.bulkActions.deletedPlural', { count: deletedIds.length }));
}
if (failedIds.length > 0) {
toast.error(failedIds.length === 1
? t('sessions.sidebar.bulkActions.failedDeleteSingle', { count: failedIds.length })
: t('sessions.sidebar.bulkActions.failedDeletePlural', { count: failedIds.length }));
// The server cascade-deletes all descendant sessions when the parent
// is removed. Only send the root session delete request; sending
// individual requests for each descendant would hit 404 (already
// deleted by cascade) and trigger rollback that restores them.
const success = await args.deleteSession(session.id);
if (success) {
const totalDeleted = descendantIds.length + 1;
toast.success(totalDeleted === 1
? t('sessions.sidebar.bulkActions.deletedSingle', { count: totalDeleted })
: t('sessions.sidebar.bulkActions.deletedPlural', { count: totalDeleted }));
} else {
toast.error(t('sessions.sidebar.session.delete.error'));
}
return;
}
+9
View File
@@ -483,6 +483,12 @@ export async function deleteSession(sessionId: string, _options?: Record<string,
return true
} catch (error) {
console.error("[session-actions] deleteSession failed", error)
// The server cascade-deletes child sessions when the parent is removed.
// Subsequent delete attempts for those children return 404; treat as
// success since the session was already deleted by the cascade.
if ((error as { status?: number })?.status === 404) {
return true
}
restoreSessionListSnapshots(snapshots)
restoreGlobalSessionSnapshot(globalSnapshot)
return false
@@ -507,6 +513,9 @@ export async function deleteSessionInDirectory(sessionId: string, directory: str
return true
} catch (error) {
console.error("[session-actions] deleteSessionInDirectory failed", error)
if ((error as { status?: number })?.status === 404) {
return true
}
restoreSessionListSnapshots(snapshots)
restoreGlobalSessionSnapshot(globalSnapshot)
return false