diff --git a/lib/shared/dm-ops/leave-thread-spec.js b/lib/shared/dm-ops/leave-thread-spec.js
--- a/lib/shared/dm-ops/leave-thread-spec.js
+++ b/lib/shared/dm-ops/leave-thread-spec.js
@@ -21,7 +21,6 @@
 import type { ClientUpdateInfo } from '../../types/update-types.js';
 import { values } from '../../utils/objects.js';
 import { rawMessageInfoFromMessageData } from '../message-utils.js';
-import { userIsMember } from '../thread-utils.js';
 
 function createMessageDataWithInfoFromDMOperation(
   dmOperation: DMLeaveThreadOperation,
@@ -37,13 +36,12 @@
   return { messageData, rawMessageInfo };
 }
 
-function createLeaveThreadSubthreadsUpdates(
+function createDeleteSubthreadsUpdates(
   dmOperation: DMLeaveThreadOperation,
   threadInfo: ThickRawThreadInfo,
-  viewerID: string,
   threadInfos: RawThreadInfos,
-): $ReadOnlyArray<ClientUpdateInfo> {
-  const updates = [];
+): Array<ClientUpdateInfo> {
+  const updates: Array<ClientUpdateInfo> = [];
   for (const thread of values(threadInfos)) {
     if (thread.parentThreadID !== threadInfo.id) {
       continue;
@@ -60,6 +58,56 @@
   return updates;
 }
 
+function createLeaveSubthreadsUpdates(
+  dmOperation: DMLeaveThreadOperation,
+  threadInfo: ThickRawThreadInfo,
+  threadInfos: RawThreadInfos,
+): Array<ClientUpdateInfo> {
+  const updates: Array<ClientUpdateInfo> = [];
+  for (const thread of values(threadInfos)) {
+    if (thread.parentThreadID !== threadInfo.id || !thread.thick) {
+      continue;
+    }
+
+    const userID = dmOperation.editorID;
+    let userTimestamps = thread.timestamps.members[userID];
+    if (!userTimestamps) {
+      userTimestamps = {
+        isMember: thread.creationTime,
+        subscription: thread.creationTime,
+      };
+    }
+
+    if (userTimestamps.isMember > dmOperation.time) {
+      continue;
+    }
+
+    const updatedThread = {
+      ...thread,
+      members: thread.members.filter(member => member.id !== userID),
+      timestamps: {
+        ...thread.timestamps,
+        members: {
+          ...thread.timestamps.members,
+          [userID]: {
+            ...userTimestamps,
+            isMember: dmOperation.time,
+          },
+        },
+      },
+    };
+
+    updates.push({
+      type: updateTypes.UPDATE_THREAD,
+      id: uuid.v4(),
+      time: dmOperation.time,
+      threadInfo: updatedThread,
+    });
+  }
+
+  return updates;
+}
+
 const leaveThreadSpec: DMOperationSpec<DMLeaveThreadOperation> = Object.freeze({
   notificationsCreationData: async (dmOperation: DMLeaveThreadOperation) => {
     return {
@@ -81,40 +129,6 @@
       createMessageDataWithInfoFromDMOperation(dmOperation);
     const rawMessageInfos = [rawMessageInfo];
 
-    if (
-      viewerID === editorID &&
-      userIsMember(threadInfo, editorID) &&
-      (threadInfo.type !== threadTypes.THICK_SIDEBAR ||
-        (threadInfo.parentThreadID && !threadInfos[threadInfo.parentThreadID]))
-    ) {
-      return {
-        rawMessageInfos,
-        updateInfos: [
-          {
-            type: updateTypes.DELETE_THREAD,
-            id: uuid.v4(),
-            time,
-            threadID,
-          },
-          ...createLeaveThreadSubthreadsUpdates(
-            dmOperation,
-            threadInfo,
-            viewerID,
-            threadInfos,
-          ),
-        ],
-        blobOps: [],
-      };
-    }
-
-    if (threadInfo.timestamps.members[editorID]?.isMember > time) {
-      return {
-        rawMessageInfos,
-        updateInfos: [],
-        blobOps: [],
-      };
-    }
-
     const memberTimestamps = { ...threadInfo.timestamps.members };
     if (!memberTimestamps[editorID]) {
       memberTimestamps[editorID] = {
@@ -127,8 +141,35 @@
       isMember: time,
     };
 
-    let currentUser = threadInfo.currentUser;
-    if (editorID === viewerID) {
+    if (viewerID === editorID) {
+      if (threadInfo.timestamps.members[editorID]?.isMember > time) {
+        return {
+          rawMessageInfos,
+          updateInfos: [],
+          blobOps: [],
+        };
+      }
+
+      if (threadInfo.type !== threadTypes.THICK_SIDEBAR) {
+        return {
+          rawMessageInfos,
+          updateInfos: [
+            {
+              type: updateTypes.DELETE_THREAD,
+              id: uuid.v4(),
+              time,
+              threadID,
+            },
+            ...createDeleteSubthreadsUpdates(
+              dmOperation,
+              threadInfo,
+              threadInfos,
+            ),
+          ],
+          blobOps: [],
+        };
+      }
+
       const parentThreadID = threadInfo.parentThreadID;
       const parentThreadInfo = parentThreadID
         ? utilities.threadInfos[parentThreadID]
@@ -149,33 +190,73 @@
         false,
         parentThreadInfo,
       );
-      const { minimallyEncoded, permissions, ...currentUserInfo } = currentUser;
-      currentUser = minimallyEncodeThreadCurrentUserInfo({
+      const { minimallyEncoded, permissions, ...currentUserInfo } =
+        threadInfo.currentUser;
+      const currentUser = minimallyEncodeThreadCurrentUserInfo({
         ...currentUserInfo,
         role: null,
         permissions: viewerMembershipPermissions,
       });
+
+      const updatedThreadInfo = {
+        ...threadInfo,
+        members: threadInfo.members.filter(member => member.id !== editorID),
+        currentUser,
+        timestamps: {
+          ...threadInfo.timestamps,
+          members: memberTimestamps,
+        },
+      };
+
+      return {
+        rawMessageInfos,
+        updateInfos: [
+          {
+            type: updateTypes.UPDATE_THREAD,
+            id: uuid.v4(),
+            time,
+            threadInfo: updatedThreadInfo,
+          },
+        ],
+        blobOps: [],
+      };
+    }
+
+    const updateInfos = createLeaveSubthreadsUpdates(
+      dmOperation,
+      threadInfo,
+      threadInfos,
+    );
+
+    // It is possible that the editor has joined this thread after leaving it,
+    // but regardless, we should possibly leave the sidebars. We need to do
+    // that because it isn't guaranteed that the editor rejoined them.
+    if (threadInfo.timestamps.members[editorID]?.isMember > time) {
+      return {
+        rawMessageInfos,
+        updateInfos,
+        blobOps: [],
+      };
     }
 
     const updatedThreadInfo = {
       ...threadInfo,
       members: threadInfo.members.filter(member => member.id !== editorID),
-      currentUser,
       timestamps: {
         ...threadInfo.timestamps,
         members: memberTimestamps,
       },
     };
+    updateInfos.push({
+      type: updateTypes.UPDATE_THREAD,
+      id: uuid.v4(),
+      time,
+      threadInfo: updatedThreadInfo,
+    });
+
     return {
       rawMessageInfos,
-      updateInfos: [
-        {
-          type: updateTypes.UPDATE_THREAD,
-          id: uuid.v4(),
-          time,
-          threadInfo: updatedThreadInfo,
-        },
-      ],
+      updateInfos,
       blobOps: [],
     };
   },