diff --git a/keyserver/src/fetchers/message-fetchers.js b/keyserver/src/fetchers/message-fetchers.js
--- a/keyserver/src/fetchers/message-fetchers.js
+++ b/keyserver/src/fetchers/message-fetchers.js
@@ -26,7 +26,7 @@
   defaultMaxMessageAge,
   type FetchPinnedMessagesRequest,
   type FetchPinnedMessagesResult,
-  isMessageSidebarSourceReactionOrEdit,
+  isMessageSidebarSourceReactionEditOrPin,
   type SearchMessagesResponse,
 } from 'lib/types/message-types.js';
 import { defaultNumberPerThread } from 'lib/types/message-types.js';
@@ -745,9 +745,9 @@
   for (const message of messages) {
     let { rawMessageInfo } = message;
     invariant(
-      !isMessageSidebarSourceReactionOrEdit(rawMessageInfo),
+      !isMessageSidebarSourceReactionEditOrPin(rawMessageInfo),
       'SIDEBAR_SOURCE or TOGGLE_PIN should not point to a ' +
-        'SIDEBAR_SOURCE, REACTION or EDIT_MESSAGE',
+        'SIDEBAR_SOURCE, REACTION, EDIT_MESSAGE or TOGGLE_PIN',
     );
     if (rawMessageInfo.id) {
       const editedContent = edits.get(rawMessageInfo.id);
@@ -849,6 +849,7 @@
       AND (
         m.type = ${messageTypes.SIDEBAR_SOURCE}
         OR m.type = ${messageTypes.REACTION}
+        OR m.type = ${messageTypes.TOGGLE_PIN}
       )
     UNION SELECT m.id, m.thread AS threadID, m.content, m.time, m.type, 
       m.creation, m.user AS creatorID, m.target_message as targetMessageID,
@@ -889,7 +890,7 @@
   >();
   for (const message of parsedResults) {
     const { rawMessageInfo } = message;
-    if (isMessageSidebarSourceReactionOrEdit(rawMessageInfo)) {
+    if (isMessageSidebarSourceReactionEditOrPin(rawMessageInfo)) {
       continue;
     }
     invariant(rawMessageInfo.id, 'rawMessageInfo.id should not be null');
diff --git a/lib/shared/messages/sidebar-source-message-spec.js b/lib/shared/messages/sidebar-source-message-spec.js
--- a/lib/shared/messages/sidebar-source-message-spec.js
+++ b/lib/shared/messages/sidebar-source-message-spec.js
@@ -16,7 +16,7 @@
   type SidebarSourceMessageData,
   type SidebarSourceMessageInfo,
   type ClientDBMessageInfo,
-  isMessageSidebarSourceReactionOrEdit,
+  isMessageSidebarSourceReactionEditOrPin,
   rawSidebarSourceMessageInfoValidator,
 } from '../../types/message-types.js';
 import type { RawUnsupportedMessageInfo } from '../../types/messages/unsupported.js';
@@ -108,8 +108,8 @@
       rawMessageInfo.sourceMessage,
     );
     invariant(
-      sourceMessage && !isMessageSidebarSourceReactionOrEdit(sourceMessage),
-      'Sidebars can not be created from SIDEBAR SOURCE, REACTION or EDIT MESSAGE',
+      sourceMessage && !isMessageSidebarSourceReactionEditOrPin(sourceMessage),
+      'Sidebars can not be created from SIDEBAR SOURCE, REACTION, EDIT OR PIN MESSAGE',
     );
 
     return {
diff --git a/lib/types/message-types.js b/lib/types/message-types.js
--- a/lib/types/message-types.js
+++ b/lib/types/message-types.js
@@ -181,13 +181,14 @@
   return messageData.localID;
 }
 
-export function isMessageSidebarSourceReactionOrEdit(
+export function isMessageSidebarSourceReactionEditOrPin(
   message: RawMessageInfo | MessageInfo,
 ): boolean %checks {
   return (
     message.type === messageTypes.SIDEBAR_SOURCE ||
     message.type === messageTypes.REACTION ||
-    message.type === messageTypes.EDIT_MESSAGE
+    message.type === messageTypes.EDIT_MESSAGE ||
+    message.type === messageTypes.TOGGLE_PIN
   );
 }
 
diff --git a/native/chat/message-results-screen.react.js b/native/chat/message-results-screen.react.js
--- a/native/chat/message-results-screen.react.js
+++ b/native/chat/message-results-screen.react.js
@@ -8,6 +8,7 @@
 import { fetchPinnedMessages } from 'lib/actions/message-actions.js';
 import { messageListData } from 'lib/selectors/chat-selectors.js';
 import { createMessageInfo } from 'lib/shared/message-utils.js';
+import { isComposableMessageType } from 'lib/types/message-types.js';
 import type { ThreadInfo } from 'lib/types/thread-types.js';
 import { useServerCall } from 'lib/utils/action-utils.js';
 
@@ -70,13 +71,11 @@
       return [];
     }
 
-    const pinnedMessageIDs = new Set();
-    translatedMessageResults.forEach(item => pinnedMessageIDs.add(item.id));
-
     const chatMessageInfoItems = chatMessageInfos.filter(
       item =>
         item.itemType === 'message' &&
-        pinnedMessageIDs.has(item.messageInfo.id),
+        item.isPinned &&
+        isComposableMessageType(item.messageInfo.type),
     );
 
     // By the nature of using messageListData and passing in
@@ -101,7 +100,7 @@
     }
 
     return sortedChatMessageInfoItems.filter(Boolean);
-  }, [translatedMessageResults, chatMessageInfos, rawMessageResults]);
+  }, [chatMessageInfos, rawMessageResults]);
 
   const measureCallback = React.useCallback(
     (listDataWithHeights: $ReadOnlyArray<ChatMessageItemWithHeight>) => {
diff --git a/web/modals/chat/message-results-modal.react.js b/web/modals/chat/message-results-modal.react.js
--- a/web/modals/chat/message-results-modal.react.js
+++ b/web/modals/chat/message-results-modal.react.js
@@ -13,6 +13,7 @@
   createMessageInfo,
   modifyItemForResultScreen,
 } from 'lib/shared/message-utils.js';
+import { isComposableMessageType } from 'lib/types/message-types.js';
 import { type ThreadInfo } from 'lib/types/thread-types.js';
 import {
   useServerCall,
@@ -75,13 +76,11 @@
       return [];
     }
 
-    const pinnedMessageIDs = new Set();
-    translatedMessageResults.forEach(item => pinnedMessageIDs.add(item.id));
-
     const chatMessageInfoItems = chatMessageInfos.filter(
       item =>
         item.itemType === 'message' &&
-        pinnedMessageIDs.has(item.messageInfo.id),
+        item.isPinned &&
+        isComposableMessageType(item.messageInfo.type),
     );
 
     // By the nature of using messageListData and passing in
@@ -106,7 +105,7 @@
     }
 
     return sortedChatMessageInfoItems;
-  }, [translatedMessageResults, chatMessageInfos, rawMessageResults]);
+  }, [chatMessageInfos, rawMessageResults]);
 
   const modifiedItems = React.useMemo(
     () =>