diff --git a/lib/shared/dm-ops/add-members-spec.js b/lib/shared/dm-ops/add-members-spec.js
--- a/lib/shared/dm-ops/add-members-spec.js
+++ b/lib/shared/dm-ops/add-members-spec.js
@@ -122,11 +122,11 @@
       updateInfos,
     };
   },
-  canBeProcessed(
+  canBeProcessed: async (
     dmOperation: DMAddMembersOperation,
     viewerID: string,
     utilities: ProcessDMOperationUtilities,
-  ) {
+  ) => {
     if (utilities.threadInfos[dmOperation.threadID]) {
       return { isProcessingPossible: true };
     }
diff --git a/lib/shared/dm-ops/add-viewer-to-thread-members-spec.js b/lib/shared/dm-ops/add-viewer-to-thread-members-spec.js
--- a/lib/shared/dm-ops/add-viewer-to-thread-members-spec.js
+++ b/lib/shared/dm-ops/add-viewer-to-thread-members-spec.js
@@ -120,10 +120,10 @@
       ];
       return { rawMessageInfos, updateInfos };
     },
-    canBeProcessed(
+    canBeProcessed: async (
       dmOperation: DMAddViewerToThreadMembersOperation,
       viewerID: string,
-    ) {
+    ) => {
       // We expect the viewer to be in the added users when the DM op
       // is processed. An exception is for ops generated
       // by InitialStateSharingHandler, which won't contain a messageID
diff --git a/lib/shared/dm-ops/change-thread-read-status-spec.js b/lib/shared/dm-ops/change-thread-read-status-spec.js
--- a/lib/shared/dm-ops/change-thread-read-status-spec.js
+++ b/lib/shared/dm-ops/change-thread-read-status-spec.js
@@ -63,11 +63,11 @@
         updateInfos,
       };
     },
-    canBeProcessed(
+    canBeProcessed: async (
       dmOperation: DMChangeThreadReadStatusOperation,
       viewerID: string,
       utilities: ProcessDMOperationUtilities,
-    ) {
+    ) => {
       const { creatorID, threadID } = dmOperation;
       if (viewerID !== creatorID) {
         return { isProcessingPossible: false, reason: { type: 'invalid' } };
diff --git a/lib/shared/dm-ops/change-thread-settings-spec.js b/lib/shared/dm-ops/change-thread-settings-spec.js
--- a/lib/shared/dm-ops/change-thread-settings-spec.js
+++ b/lib/shared/dm-ops/change-thread-settings-spec.js
@@ -161,11 +161,11 @@
         updateInfos,
       };
     },
-    canBeProcessed(
+    canBeProcessed: async (
       dmOperation: DMChangeThreadSettingsOperation,
       viewerID: string,
       utilities: ProcessDMOperationUtilities,
-    ) {
+    ) => {
       if (utilities.threadInfos[dmOperation.threadID]) {
         return { isProcessingPossible: true };
       }
diff --git a/lib/shared/dm-ops/change-thread-subscription.js b/lib/shared/dm-ops/change-thread-subscription.js
--- a/lib/shared/dm-ops/change-thread-subscription.js
+++ b/lib/shared/dm-ops/change-thread-subscription.js
@@ -77,11 +77,11 @@
 
       return { updateInfos, rawMessageInfos: [] };
     },
-    canBeProcessed(
+    canBeProcessed: async (
       dmOperation: DMChangeThreadSubscriptionOperation,
       viewerID: string,
       utilities: ProcessDMOperationUtilities,
-    ) {
+    ) => {
       const { threadID, creatorID } = dmOperation;
       if (!utilities.threadInfos[threadID]) {
         return {
@@ -95,7 +95,10 @@
           memberInfo => memberInfo.id === creatorID,
         )
       ) {
-        return { isProcessingPossible: false, reason: { type: 'invalid' } };
+        return {
+          isProcessingPossible: false,
+          reason: { type: 'missing_membership', threadID, userID: creatorID },
+        };
       }
 
       return { isProcessingPossible: true };
diff --git a/lib/shared/dm-ops/create-entry-spec.js b/lib/shared/dm-ops/create-entry-spec.js
--- a/lib/shared/dm-ops/create-entry-spec.js
+++ b/lib/shared/dm-ops/create-entry-spec.js
@@ -68,11 +68,11 @@
       updateInfos: [entryUpdateInfo],
     };
   },
-  canBeProcessed(
+  canBeProcessed: async (
     dmOperation: DMCreateEntryOperation,
     viewerID: string,
     utilities: ProcessDMOperationUtilities,
-  ) {
+  ) => {
     if (utilities.threadInfos[dmOperation.threadID]) {
       return { isProcessingPossible: true };
     }
diff --git a/lib/shared/dm-ops/create-sidebar-spec.js b/lib/shared/dm-ops/create-sidebar-spec.js
--- a/lib/shared/dm-ops/create-sidebar-spec.js
+++ b/lib/shared/dm-ops/create-sidebar-spec.js
@@ -166,7 +166,23 @@
         updateInfos: [threadJoinUpdateInfo],
       };
     },
-    canBeProcessed() {
+    canBeProcessed: async (
+      dmOperation: DMCreateSidebarOperation,
+      viewerID: string,
+      utilities: ProcessDMOperationUtilities,
+    ) => {
+      const sourceMessage = await utilities.fetchMessage(
+        dmOperation.sourceMessageID,
+      );
+      if (!sourceMessage) {
+        return {
+          isProcessingPossible: false,
+          reason: {
+            type: 'missing_message',
+            messageID: dmOperation.sourceMessageID,
+          },
+        };
+      }
       return { isProcessingPossible: true };
     },
     supportsAutoRetry: true,
diff --git a/lib/shared/dm-ops/create-thread-spec.js b/lib/shared/dm-ops/create-thread-spec.js
--- a/lib/shared/dm-ops/create-thread-spec.js
+++ b/lib/shared/dm-ops/create-thread-spec.js
@@ -206,7 +206,7 @@
         updateInfos: [threadJoinUpdateInfo],
       };
     },
-    canBeProcessed() {
+    canBeProcessed: async () => {
       return { isProcessingPossible: true };
     },
     supportsAutoRetry: true,
diff --git a/lib/shared/dm-ops/delete-entry-spec.js b/lib/shared/dm-ops/delete-entry-spec.js
--- a/lib/shared/dm-ops/delete-entry-spec.js
+++ b/lib/shared/dm-ops/delete-entry-spec.js
@@ -92,20 +92,22 @@
       updateInfos: [entryUpdateInfo],
     };
   },
-  canBeProcessed(
+  canBeProcessed: async (
     dmOperation: DMDeleteEntryOperation,
     viewerID: string,
     utilities: ProcessDMOperationUtilities,
-  ) {
-    if (utilities.threadInfos[dmOperation.threadID]) {
-      return { isProcessingPossible: true };
+  ) => {
+    if (!utilities.entryInfos[dmOperation.entryID]) {
+      return {
+        isProcessingPossible: false,
+        reason: {
+          type: 'missing_entry',
+          entryID: dmOperation.entryID,
+        },
+      };
     }
     return {
-      isProcessingPossible: false,
-      reason: {
-        type: 'missing_thread',
-        threadID: dmOperation.threadID,
-      },
+      isProcessingPossible: true,
     };
   },
   supportsAutoRetry: true,
diff --git a/lib/shared/dm-ops/dm-op-spec.js b/lib/shared/dm-ops/dm-op-spec.js
--- a/lib/shared/dm-ops/dm-op-spec.js
+++ b/lib/shared/dm-ops/dm-op-spec.js
@@ -13,6 +13,18 @@
   +entryInfos: RawEntryInfos,
 };
 
+type ProcessingPossibilityCheckResult =
+  | { +isProcessingPossible: true }
+  | {
+      +isProcessingPossible: false,
+      +reason:
+        | { +type: 'missing_thread', +threadID: string }
+        | { +type: 'missing_entry', +entryID: string }
+        | { +type: 'missing_message', +messageID: string }
+        | { +type: 'missing_membership', +threadID: string, +userID: string }
+        | { +type: 'invalid' },
+    };
+
 export type DMOperationSpec<DMOp: DMOperation> = {
   +notificationsCreationData?: (
     dmOp: DMOp,
@@ -27,16 +39,6 @@
     dmOp: DMOp,
     viewerID: string,
     utilities: ProcessDMOperationUtilities,
-  ) =>
-    | { +isProcessingPossible: true }
-    | {
-        +isProcessingPossible: false,
-        +reason:
-          | { +type: 'missing_thread', +threadID: string }
-          | { +type: 'missing_entry', +entryID: string }
-          | { +type: 'missing_message', +messageID: string }
-          | { +type: 'missing_membership', +threadID: string, +userID: string }
-          | { +type: 'invalid' },
-      },
+  ) => Promise<ProcessingPossibilityCheckResult>,
   +supportsAutoRetry: boolean,
 };
diff --git a/lib/shared/dm-ops/edit-entry-spec.js b/lib/shared/dm-ops/edit-entry-spec.js
--- a/lib/shared/dm-ops/edit-entry-spec.js
+++ b/lib/shared/dm-ops/edit-entry-spec.js
@@ -92,20 +92,22 @@
       updateInfos: [entryUpdateInfo],
     };
   },
-  canBeProcessed(
+  canBeProcessed: async (
     dmOperation: DMEditEntryOperation,
     viewerID: string,
     utilities: ProcessDMOperationUtilities,
-  ) {
-    if (utilities.threadInfos[dmOperation.threadID]) {
-      return { isProcessingPossible: true };
+  ) => {
+    if (!utilities.entryInfos[dmOperation.entryID]) {
+      return {
+        isProcessingPossible: false,
+        reason: {
+          type: 'missing_entry',
+          entryID: dmOperation.entryID,
+        },
+      };
     }
     return {
-      isProcessingPossible: false,
-      reason: {
-        type: 'missing_thread',
-        threadID: dmOperation.threadID,
-      },
+      isProcessingPossible: true,
     };
   },
   supportsAutoRetry: true,
diff --git a/lib/shared/dm-ops/join-thread-spec.js b/lib/shared/dm-ops/join-thread-spec.js
--- a/lib/shared/dm-ops/join-thread-spec.js
+++ b/lib/shared/dm-ops/join-thread-spec.js
@@ -162,11 +162,11 @@
       updateInfos,
     };
   },
-  canBeProcessed(
+  canBeProcessed: async (
     dmOperation: DMJoinThreadOperation,
     viewerID: string,
     utilities: ProcessDMOperationUtilities,
-  ) {
+  ) => {
     if (
       utilities.threadInfos[dmOperation.existingThreadDetails.threadID] ||
       dmOperation.joinerID === viewerID
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
@@ -135,11 +135,11 @@
       ],
     };
   },
-  canBeProcessed(
+  canBeProcessed: async (
     dmOperation: DMLeaveThreadOperation,
     viewerID: string,
     utilities: ProcessDMOperationUtilities,
-  ) {
+  ) => {
     if (utilities.threadInfos[dmOperation.threadID]) {
       return { isProcessingPossible: true };
     }
diff --git a/lib/shared/dm-ops/process-dm-ops.js b/lib/shared/dm-ops/process-dm-ops.js
--- a/lib/shared/dm-ops/process-dm-ops.js
+++ b/lib/shared/dm-ops/process-dm-ops.js
@@ -142,7 +142,7 @@
         return;
       }
 
-      const processingCheckResult = dmOpSpecs[dmOp.type].canBeProcessed(
+      const processingCheckResult = await dmOpSpecs[dmOp.type].canBeProcessed(
         dmOp,
         viewerID,
         utilities,
diff --git a/lib/shared/dm-ops/remove-members-spec.js b/lib/shared/dm-ops/remove-members-spec.js
--- a/lib/shared/dm-ops/remove-members-spec.js
+++ b/lib/shared/dm-ops/remove-members-spec.js
@@ -109,11 +109,11 @@
         updateInfos,
       };
     },
-    canBeProcessed(
+    canBeProcessed: async (
       dmOperation: DMRemoveMembersOperation,
       viewerID: string,
       utilities: ProcessDMOperationUtilities,
-    ) {
+    ) => {
       if (utilities.threadInfos[dmOperation.threadID]) {
         return { isProcessingPossible: true };
       }
diff --git a/lib/shared/dm-ops/send-edit-message-spec.js b/lib/shared/dm-ops/send-edit-message-spec.js
--- a/lib/shared/dm-ops/send-edit-message-spec.js
+++ b/lib/shared/dm-ops/send-edit-message-spec.js
@@ -42,20 +42,23 @@
         updateInfos: [],
       };
     },
-    canBeProcessed(
+    canBeProcessed: async (
       dmOperation: DMSendEditMessageOperation,
       viewerID: string,
       utilities: ProcessDMOperationUtilities,
-    ) {
-      if (utilities.threadInfos[dmOperation.threadID]) {
-        return { isProcessingPossible: true };
+    ) => {
+      const message = await utilities.fetchMessage(dmOperation.targetMessageID);
+      if (!message) {
+        return {
+          isProcessingPossible: false,
+          reason: {
+            type: 'missing_message',
+            messageID: dmOperation.targetMessageID,
+          },
+        };
       }
       return {
-        isProcessingPossible: false,
-        reason: {
-          type: 'missing_thread',
-          threadID: dmOperation.threadID,
-        },
+        isProcessingPossible: true,
       };
     },
     supportsAutoRetry: true,
diff --git a/lib/shared/dm-ops/send-multimedia-message-spec.js b/lib/shared/dm-ops/send-multimedia-message-spec.js
--- a/lib/shared/dm-ops/send-multimedia-message-spec.js
+++ b/lib/shared/dm-ops/send-multimedia-message-spec.js
@@ -45,11 +45,11 @@
         updateInfos,
       };
     },
-    canBeProcessed(
+    canBeProcessed: async (
       dmOperation: DMSendMultimediaMessageOperation,
       viewerID: string,
       utilities: ProcessDMOperationUtilities,
-    ) {
+    ) => {
       if (utilities.threadInfos[dmOperation.threadID]) {
         return { isProcessingPossible: true };
       }
diff --git a/lib/shared/dm-ops/send-reaction-message-spec.js b/lib/shared/dm-ops/send-reaction-message-spec.js
--- a/lib/shared/dm-ops/send-reaction-message-spec.js
+++ b/lib/shared/dm-ops/send-reaction-message-spec.js
@@ -44,20 +44,23 @@
         updateInfos: [],
       };
     },
-    canBeProcessed(
+    canBeProcessed: async (
       dmOperation: DMSendReactionMessageOperation,
       viewerID: string,
       utilities: ProcessDMOperationUtilities,
-    ) {
-      if (utilities.threadInfos[dmOperation.threadID]) {
-        return { isProcessingPossible: true };
+    ) => {
+      const message = await utilities.fetchMessage(dmOperation.targetMessageID);
+      if (!message) {
+        return {
+          isProcessingPossible: false,
+          reason: {
+            type: 'missing_message',
+            messageID: dmOperation.targetMessageID,
+          },
+        };
       }
       return {
-        isProcessingPossible: false,
-        reason: {
-          type: 'missing_thread',
-          threadID: dmOperation.threadID,
-        },
+        isProcessingPossible: true,
       };
     },
     supportsAutoRetry: true,
diff --git a/lib/shared/dm-ops/send-text-message-spec.js b/lib/shared/dm-ops/send-text-message-spec.js
--- a/lib/shared/dm-ops/send-text-message-spec.js
+++ b/lib/shared/dm-ops/send-text-message-spec.js
@@ -42,11 +42,11 @@
         updateInfos,
       };
     },
-    canBeProcessed(
+    canBeProcessed: async (
       dmOperation: DMSendTextMessageOperation,
       viewerID: string,
       utilities: ProcessDMOperationUtilities,
-    ) {
+    ) => {
       if (utilities.threadInfos[dmOperation.threadID]) {
         return { isProcessingPossible: true };
       }