diff --git a/lib/actions/activity-actions.js b/lib/actions/activity-actions.js
--- a/lib/actions/activity-actions.js
+++ b/lib/actions/activity-actions.js
@@ -1,7 +1,5 @@
 // @flow
 
-import invariant from 'invariant';
-
 import { extractKeyserverIDFromID } from '../keyserver-conn/keyserver-call-utils.js';
 import { useKeyserverCall } from '../keyserver-conn/keyserver-call.js';
 import type { CallKeyserverEndpoint } from '../keyserver-conn/keyserver-conn-types.js';
@@ -29,9 +27,7 @@
     const { activityUpdates } = input;
     const requests: { [string]: { +updates: ActivityUpdate[] } } = {};
     for (const update of activityUpdates) {
-      const optionalKeyserverID = extractKeyserverIDFromID(update.threadID);
-      invariant(optionalKeyserverID, 'Keyserver ID should be present');
-      const keyserverID: string = optionalKeyserverID;
+      const keyserverID = extractKeyserverIDFromID(update.threadID);
       if (!requests[keyserverID]) {
         requests[keyserverID] = { updates: [] };
       }
@@ -80,9 +76,7 @@
     input: SetThreadUnreadStatusRequest,
   ) => Promise<SetThreadUnreadStatusPayload>) =>
   async input => {
-    const optionalKeyserverID = extractKeyserverIDFromID(input.threadID);
-    invariant(optionalKeyserverID, 'Keyserver ID should be present');
-    const keyserverID: string = optionalKeyserverID;
+    const keyserverID = extractKeyserverIDFromID(input.threadID);
     const requests = { [keyserverID]: input };
 
     const responses = await callKeyserverEndpoint(
diff --git a/lib/actions/community-actions.js b/lib/actions/community-actions.js
--- a/lib/actions/community-actions.js
+++ b/lib/actions/community-actions.js
@@ -1,7 +1,5 @@
 // @flow
 
-import invariant from 'invariant';
-
 import { extractKeyserverIDFromID } from '../keyserver-conn/keyserver-call-utils.js';
 import { useKeyserverCall } from '../keyserver-conn/keyserver-call.js';
 import type { CallKeyserverEndpoint } from '../keyserver-conn/keyserver-conn-types.js';
@@ -74,9 +72,7 @@
     input: CreateOrUpdateFarcasterChannelTagRequest,
   ) => Promise<CreateOrUpdateFarcasterChannelTagResponse>) =>
   async input => {
-    const optionalKeyserverID = extractKeyserverIDFromID(input.commCommunityID);
-    invariant(optionalKeyserverID, 'Keyserver ID should be present');
-    const keyserverID: string = optionalKeyserverID;
+    const keyserverID = extractKeyserverIDFromID(input.commCommunityID);
 
     const requests = {
       [keyserverID]: {
@@ -117,9 +113,7 @@
     input: DeleteFarcasterChannelTagRequest,
   ) => Promise<DeleteFarcasterChannelTagPayload>) =>
   async input => {
-    const optionalKeyserverID = extractKeyserverIDFromID(input.commCommunityID);
-    invariant(optionalKeyserverID, 'Keyserver ID should be present');
-    const keyserverID: string = optionalKeyserverID;
+    const keyserverID = extractKeyserverIDFromID(input.commCommunityID);
 
     const requests = {
       [keyserverID]: {
diff --git a/lib/actions/entry-actions.js b/lib/actions/entry-actions.js
--- a/lib/actions/entry-actions.js
+++ b/lib/actions/entry-actions.js
@@ -1,7 +1,5 @@
 // @flow
 
-import invariant from 'invariant';
-
 import {
   extractKeyserverIDFromID,
   sortCalendarQueryPerKeyserver,
@@ -158,9 +156,7 @@
     callKeyserverEndpoint: CallKeyserverEndpoint,
   ): ((input: CreateEntryInfo) => Promise<CreateEntryPayload>) =>
   async input => {
-    const optionalKeyserverID = extractKeyserverIDFromID(input.threadID);
-    invariant(optionalKeyserverID, 'Keyserver ID should be present');
-    const keyserverID: string = optionalKeyserverID;
+    const keyserverID = extractKeyserverIDFromID(input.threadID);
     const calendarQueries = sortCalendarQueryPerKeyserver(input.calendarQuery, [
       keyserverID,
     ]);
@@ -199,9 +195,7 @@
     callKeyserverEndpoint: CallKeyserverEndpoint,
   ): ((input: SaveEntryInfo) => Promise<SaveEntryResult>) =>
   async input => {
-    const optionalKeyserverID = extractKeyserverIDFromID(input.entryID);
-    invariant(optionalKeyserverID, 'Keyserver ID should be present');
-    const keyserverID: string = optionalKeyserverID;
+    const keyserverID = extractKeyserverIDFromID(input.entryID);
     const calendarQueries = sortCalendarQueryPerKeyserver(input.calendarQuery, [
       keyserverID,
     ]);
@@ -235,9 +229,7 @@
     callKeyserverEndpoint: CallKeyserverEndpoint,
   ): ((info: DeleteEntryInfo) => Promise<DeleteEntryResult>) =>
   async input => {
-    const optionalKeyserverID = extractKeyserverIDFromID(input.entryID);
-    invariant(optionalKeyserverID, 'Keyserver ID should be present');
-    const keyserverID: string = optionalKeyserverID;
+    const keyserverID = extractKeyserverIDFromID(input.entryID);
     const calendarQueries = sortCalendarQueryPerKeyserver(input.calendarQuery, [
       keyserverID,
     ]);
@@ -279,9 +271,7 @@
     input: FetchRevisionsForEntryInput,
   ) => Promise<$ReadOnlyArray<HistoryRevisionInfo>>) =>
   async input => {
-    const optionalKeyserverID = extractKeyserverIDFromID(input.entryID);
-    invariant(optionalKeyserverID, 'Keyserver ID should be present');
-    const keyserverID: string = optionalKeyserverID;
+    const keyserverID = extractKeyserverIDFromID(input.entryID);
     const requests = {
       [keyserverID]: {
         id: input.entryID,
@@ -311,9 +301,7 @@
     callKeyserverEndpoint: CallKeyserverEndpoint,
   ): ((input: RestoreEntryInfo) => Promise<RestoreEntryResult>) =>
   async input => {
-    const optionalKeyserverID = extractKeyserverIDFromID(input.entryID);
-    invariant(optionalKeyserverID, 'Keyserver ID should be present');
-    const keyserverID: string = optionalKeyserverID;
+    const keyserverID = extractKeyserverIDFromID(input.entryID);
     const calendarQueries = sortCalendarQueryPerKeyserver(input.calendarQuery, [
       keyserverID,
     ]);
diff --git a/lib/actions/link-actions.js b/lib/actions/link-actions.js
--- a/lib/actions/link-actions.js
+++ b/lib/actions/link-actions.js
@@ -1,5 +1,5 @@
 // @flow
-import invariant from 'invariant';
+
 import * as React from 'react';
 
 import type { CallSingleKeyserverEndpoint } from '../keyserver-conn/call-single-keyserver-endpoint.js';
@@ -130,9 +130,7 @@
     callKeyserverEndpoint: CallKeyserverEndpoint,
   ): ((input: CreateOrUpdatePublicLinkRequest) => Promise<InviteLink>) =>
   async input => {
-    const optionalKeyserverID = extractKeyserverIDFromID(input.communityID);
-    invariant(optionalKeyserverID, 'Keyserver ID should be present');
-    const keyserverID: string = optionalKeyserverID;
+    const keyserverID = extractKeyserverIDFromID(input.communityID);
     const requests = {
       [keyserverID]: {
         name: input.name,
@@ -173,9 +171,7 @@
     callKeyserverEndpoint: CallKeyserverEndpoint,
   ): ((input: DisableInviteLinkRequest) => Promise<DisableInviteLinkPayload>) =>
   async input => {
-    const optionalKeyserverID = extractKeyserverIDFromID(input.communityID);
-    invariant(optionalKeyserverID, 'Keyserver ID should be present');
-    const keyserverID: string = optionalKeyserverID;
+    const keyserverID = extractKeyserverIDFromID(input.communityID);
     const requests = { [keyserverID]: input };
 
     await callKeyserverEndpoint('disable_invite_link', requests);
diff --git a/lib/actions/message-actions.js b/lib/actions/message-actions.js
--- a/lib/actions/message-actions.js
+++ b/lib/actions/message-actions.js
@@ -48,9 +48,7 @@
   async input => {
     const { threadID, beforeMessageID } = input;
 
-    const optionalKeyserverID = extractKeyserverIDFromID(input.threadID);
-    invariant(optionalKeyserverID, 'Keyserver ID should be present');
-    const keyserverID: string = optionalKeyserverID;
+    const keyserverID = extractKeyserverIDFromID(input.threadID);
     const requests = {
       [keyserverID]: {
         cursors: {
@@ -91,9 +89,7 @@
   async input => {
     const { threadID } = input;
 
-    const optionalKeyserverID = extractKeyserverIDFromID(input.threadID);
-    invariant(optionalKeyserverID, 'Keyserver ID should be present');
-    const keyserverID: string = optionalKeyserverID;
+    const keyserverID = extractKeyserverIDFromID(input.threadID);
     const requests = {
       [keyserverID]: {
         cursors: {
@@ -193,9 +189,7 @@
       payload = { ...payload, sidebarCreation };
     }
 
-    const optionalKeyserverID = extractKeyserverIDFromID(input.threadID);
-    invariant(optionalKeyserverID, 'Keyserver ID should be present');
-    const keyserverID: string = optionalKeyserverID;
+    const keyserverID = extractKeyserverIDFromID(input.threadID);
     const requests = { [keyserverID]: payload };
 
     const responses = await callKeyserverEndpoint(
@@ -254,9 +248,7 @@
       payload = { ...payload, sidebarCreation };
     }
 
-    const optionalKeyserverID = extractKeyserverIDFromID(input.threadID);
-    invariant(optionalKeyserverID, 'Keyserver ID should be present');
-    const keyserverID: string = optionalKeyserverID;
+    const keyserverID = extractKeyserverIDFromID(input.threadID);
     const requests = { [keyserverID]: payload };
 
     const responses = await callKeyserverEndpoint(
@@ -308,9 +300,7 @@
       payload = { ...payload, sidebarCreation };
     }
 
-    const optionalKeyserverID = extractKeyserverIDFromID(input.threadID);
-    invariant(optionalKeyserverID, 'Keyserver ID should be present');
-    const keyserverID: string = optionalKeyserverID;
+    const keyserverID = extractKeyserverIDFromID(input.threadID);
     const requests = { [keyserverID]: payload };
 
     const responses = await callKeyserverEndpoint(
@@ -353,9 +343,7 @@
       resultInfo = passedResultInfo;
     };
 
-    const optionalKeyserverID = extractKeyserverIDFromID(input.threadID);
-    invariant(optionalKeyserverID, 'Keyserver ID should be present');
-    const keyserverID: string = optionalKeyserverID;
+    const keyserverID = extractKeyserverIDFromID(input.threadID);
     const requests = {
       [keyserverID]: {
         threadID: input.threadID,
@@ -401,9 +389,7 @@
     callKeyserverEndpoint: CallKeyserverEndpoint,
   ): ((input: SendEditMessageRequest) => Promise<SendEditMessageResult>) =>
   async input => {
-    const optionalKeyserverID = extractKeyserverIDFromID(input.targetMessageID);
-    invariant(optionalKeyserverID, 'Keyserver ID should be present');
-    const keyserverID: string = optionalKeyserverID;
+    const keyserverID = extractKeyserverIDFromID(input.targetMessageID);
     const requests = {
       [keyserverID]: {
         targetMessageID: input.targetMessageID,
@@ -440,9 +426,7 @@
     input: FetchPinnedMessagesRequest,
   ) => Promise<FetchPinnedMessagesResult>) =>
   async input => {
-    const optionalKeyserverID = extractKeyserverIDFromID(input.threadID);
-    invariant(optionalKeyserverID, 'Keyserver ID should be present');
-    const keyserverID: string = optionalKeyserverID;
+    const keyserverID = extractKeyserverIDFromID(input.threadID);
     const requests = { [keyserverID]: input };
 
     const responses = await callKeyserverEndpoint(
@@ -470,9 +454,7 @@
     callKeyserverEndpoint: CallKeyserverEndpoint,
   ): ((input: SearchMessagesRequest) => Promise<SearchMessagesResponse>) =>
   async input => {
-    const optionalKeyserverID = extractKeyserverIDFromID(input.threadID);
-    invariant(optionalKeyserverID, 'Keyserver ID should be present');
-    const keyserverID: string = optionalKeyserverID;
+    const keyserverID = extractKeyserverIDFromID(input.threadID);
     const requests = { [keyserverID]: input };
 
     const responses = await callKeyserverEndpoint('search_messages', requests);
@@ -499,9 +481,7 @@
     callKeyserverEndpoint: CallKeyserverEndpoint,
   ): ((input: ToggleMessagePinRequest) => Promise<ToggleMessagePinResult>) =>
   async input => {
-    const optionalKeyserverID = extractKeyserverIDFromID(input.messageID);
-    invariant(optionalKeyserverID, 'Keyserver ID should be present');
-    const keyserverID: string = optionalKeyserverID;
+    const keyserverID = extractKeyserverIDFromID(input.messageID);
     const requests = { [keyserverID]: input };
 
     const responses = await callKeyserverEndpoint(
diff --git a/lib/actions/message-report-actions.js b/lib/actions/message-report-actions.js
--- a/lib/actions/message-report-actions.js
+++ b/lib/actions/message-report-actions.js
@@ -1,7 +1,5 @@
 // @flow
 
-import invariant from 'invariant';
-
 import { extractKeyserverIDFromID } from '../keyserver-conn/keyserver-call-utils.js';
 import { useKeyserverCall } from '../keyserver-conn/keyserver-call.js';
 import type { CallKeyserverEndpoint } from '../keyserver-conn/keyserver-conn-types.js';
@@ -22,9 +20,7 @@
     input: MessageReportCreationRequest,
   ) => Promise<MessageReportCreationResult>) =>
   async input => {
-    const optionalKeyserverID = extractKeyserverIDFromID(input.messageID);
-    invariant(optionalKeyserverID, 'Keyserver ID should be present');
-    const keyserverID: string = optionalKeyserverID;
+    const keyserverID = extractKeyserverIDFromID(input.messageID);
     const requests = { [keyserverID]: input };
 
     const responses = await callKeyserverEndpoint(
diff --git a/lib/actions/thread-actions.js b/lib/actions/thread-actions.js
--- a/lib/actions/thread-actions.js
+++ b/lib/actions/thread-actions.js
@@ -43,9 +43,7 @@
     callKeyserverEndpoint: CallKeyserverEndpoint,
   ): ((input: DeleteThreadInput) => Promise<LeaveThreadPayload>) =>
   async input => {
-    const optionalKeyserverID = extractKeyserverIDFromID(input.threadID);
-    invariant(optionalKeyserverID, 'Keyserver ID should be present');
-    const keyserverID: string = optionalKeyserverID;
+    const keyserverID = extractKeyserverIDFromID(input.threadID);
     const requests = { [keyserverID]: input };
 
     const responses = await callKeyserverEndpoint(
@@ -83,9 +81,7 @@
       Object.keys(input.changes).length > 0,
       'No changes provided to changeThreadSettings!',
     );
-    const optionalKeyserverID = extractKeyserverIDFromID(input.threadID);
-    invariant(optionalKeyserverID, 'Keyserver ID should be present');
-    const keyserverID: string = optionalKeyserverID;
+    const keyserverID = extractKeyserverIDFromID(input.threadID);
     const requests = { [keyserverID]: input };
 
     const responses = await callKeyserverEndpoint(
@@ -129,9 +125,7 @@
     input: RemoveUsersFromThreadInput,
   ) => Promise<ChangeThreadSettingsPayload>) =>
   async input => {
-    const optionalKeyserverID = extractKeyserverIDFromID(input.threadID);
-    invariant(optionalKeyserverID, 'Keyserver ID should be present');
-    const keyserverID: string = optionalKeyserverID;
+    const keyserverID = extractKeyserverIDFromID(input.threadID);
     const requests = { [keyserverID]: input };
 
     const responses = await callKeyserverEndpoint(
@@ -177,9 +171,7 @@
   ) => Promise<ChangeThreadSettingsPayload>) =>
   async input => {
     const { threadID, memberIDs, newRole } = input;
-    const optionalKeyserverID = extractKeyserverIDFromID(input.threadID);
-    invariant(optionalKeyserverID, 'Keyserver ID should be present');
-    const keyserverID: string = optionalKeyserverID;
+    const keyserverID = extractKeyserverIDFromID(input.threadID);
     const requests = {
       [keyserverID]: {
         threadID,
@@ -218,9 +210,7 @@
   ): ((input: ClientNewThinThreadRequest) => Promise<NewThreadResult>) =>
   async input => {
     const parentThreadID = input.parentThreadID ?? genesis().id;
-    const optionalKeyserverID = extractKeyserverIDFromID(parentThreadID);
-    invariant(optionalKeyserverID, 'Keyserver ID should be present');
-    const keyserverID: string = optionalKeyserverID;
+    const keyserverID = extractKeyserverIDFromID(parentThreadID);
     const requests = { [keyserverID]: input };
 
     const responses = await callKeyserverEndpoint('create_thread', requests);
@@ -250,9 +240,7 @@
     callKeyserverEndpoint: CallKeyserverEndpoint,
   ): ((input: ClientThreadJoinRequest) => Promise<ThreadJoinPayload>) =>
   async input => {
-    const optionalKeyserverID = extractKeyserverIDFromID(input.threadID);
-    invariant(optionalKeyserverID, 'Keyserver ID should be present');
-    const keyserverID: string = optionalKeyserverID;
+    const keyserverID = extractKeyserverIDFromID(input.threadID);
     const requests = { [keyserverID]: input };
 
     const responses = await callKeyserverEndpoint('join_thread', requests);
@@ -286,9 +274,7 @@
     callKeyserverEndpoint: CallKeyserverEndpoint,
   ): ((input: LeaveThreadInput) => Promise<LeaveThreadPayload>) =>
   async input => {
-    const optionalKeyserverID = extractKeyserverIDFromID(input.threadID);
-    invariant(optionalKeyserverID, 'Keyserver ID should be present');
-    const keyserverID: string = optionalKeyserverID;
+    const keyserverID = extractKeyserverIDFromID(input.threadID);
     const requests = { [keyserverID]: input };
 
     const responses = await callKeyserverEndpoint('leave_thread', requests);
@@ -309,9 +295,7 @@
     callKeyserverEndpoint: CallKeyserverEndpoint,
   ): ((input: ThreadFetchMediaRequest) => Promise<ThreadFetchMediaResult>) =>
   async input => {
-    const optionalKeyserverID = extractKeyserverIDFromID(input.threadID);
-    invariant(optionalKeyserverID, 'Keyserver ID should be present');
-    const keyserverID: string = optionalKeyserverID;
+    const keyserverID = extractKeyserverIDFromID(input.threadID);
     const requests = { [keyserverID]: input };
 
     const responses = await callKeyserverEndpoint(
@@ -338,9 +322,7 @@
     callKeyserverEndpoint: CallKeyserverEndpoint,
   ): ((input: RoleModificationRequest) => Promise<RoleModificationPayload>) =>
   async input => {
-    const optionalKeyserverID = extractKeyserverIDFromID(input.community);
-    invariant(optionalKeyserverID, 'Keyserver ID should be present');
-    const keyserverID: string = optionalKeyserverID;
+    const keyserverID = extractKeyserverIDFromID(input.community);
     const requests = { [keyserverID]: input };
 
     const responses = await callKeyserverEndpoint(
@@ -370,9 +352,7 @@
     callKeyserverEndpoint: CallKeyserverEndpoint,
   ): ((input: RoleDeletionRequest) => Promise<RoleDeletionPayload>) =>
   async input => {
-    const optionalKeyserverID = extractKeyserverIDFromID(input.community);
-    invariant(optionalKeyserverID, 'Keyserver ID should be present');
-    const keyserverID: string = optionalKeyserverID;
+    const keyserverID = extractKeyserverIDFromID(input.community);
     const requests = { [keyserverID]: input };
 
     const responses = await callKeyserverEndpoint(
diff --git a/lib/actions/upload-actions.js b/lib/actions/upload-actions.js
--- a/lib/actions/upload-actions.js
+++ b/lib/actions/upload-actions.js
@@ -6,7 +6,7 @@
 
 import blobService from '../facts/blob-service.js';
 import type { CallSingleKeyserverEndpoint } from '../keyserver-conn/call-single-keyserver-endpoint.js';
-import { extractKeyserverIDFromID } from '../keyserver-conn/keyserver-call-utils.js';
+import { extractKeyserverIDFromIDOptional } from '../keyserver-conn/keyserver-call-utils.js';
 import { useKeyserverCall } from '../keyserver-conn/keyserver-call.js';
 import type { CallKeyserverEndpoint } from '../keyserver-conn/keyserver-conn-types.js';
 import { type PerformHTTPMultipartUpload } from '../keyserver-conn/multipart-upload.js';
@@ -115,10 +115,9 @@
   ): ((input: DeleteUploadInput) => Promise<void>) =>
   async input => {
     const { id, keyserverOrThreadID } = input;
-    const optionalKeyserverID =
-      extractKeyserverIDFromID(keyserverOrThreadID) ?? keyserverOrThreadID;
-    invariant(optionalKeyserverID, 'Keyserver ID should be present');
-    const keyserverID: string = optionalKeyserverID;
+    const keyserverID: string =
+      extractKeyserverIDFromIDOptional(keyserverOrThreadID) ??
+      keyserverOrThreadID;
     const requests = { [keyserverID]: { id } };
     await callKeyserverEndpoint('delete_upload', requests);
   };
@@ -227,10 +226,9 @@
     }
 
     // 3. Upload metadata to keyserver
-    const optionalKeyserverID =
-      extractKeyserverIDFromID(keyserverOrThreadID) ?? keyserverOrThreadID;
-    invariant(optionalKeyserverID, 'Keyserver ID should be present');
-    const keyserverID: string = optionalKeyserverID;
+    const keyserverID: string =
+      extractKeyserverIDFromIDOptional(keyserverOrThreadID) ??
+      keyserverOrThreadID;
     const requests = {
       [keyserverID]: {
         blobHash,
diff --git a/lib/actions/user-actions.js b/lib/actions/user-actions.js
--- a/lib/actions/user-actions.js
+++ b/lib/actions/user-actions.js
@@ -1149,9 +1149,7 @@
     input: SubscriptionUpdateRequest,
   ) => Promise<SubscriptionUpdateResult>) =>
   async input => {
-    const optionalKeyserverID = extractKeyserverIDFromID(input.threadID);
-    invariant(optionalKeyserverID, 'Keyserver ID should be present');
-    const keyserverID: string = optionalKeyserverID;
+    const keyserverID = extractKeyserverIDFromID(input.threadID);
     const requests = { [keyserverID]: input };
 
     const responses = await callKeyserverEndpoint(
diff --git a/lib/hooks/invite-links.js b/lib/hooks/invite-links.js
--- a/lib/hooks/invite-links.js
+++ b/lib/hooks/invite-links.js
@@ -1,6 +1,5 @@
 // @flow
 
-import invariant from 'invariant';
 import * as React from 'react';
 
 import { addKeyserverActionType } from '../actions/keyserver-actions.js';
@@ -185,9 +184,7 @@
   const communityID = verificationResponse.community?.id;
   let keyserverID = keyserverOverride?.keyserverID;
   if (!keyserverID && communityID) {
-    const optionalKeyserverID = extractKeyserverIDFromID(communityID);
-    invariant(optionalKeyserverID, 'Keyserver ID should be present');
-    keyserverID = optionalKeyserverID;
+    keyserverID = extractKeyserverIDFromID(communityID);
   }
 
   const isKeyserverKnown = useSelector(state =>
diff --git a/lib/keyserver-conn/keyserver-call-utils.js b/lib/keyserver-conn/keyserver-call-utils.js
--- a/lib/keyserver-conn/keyserver-call-utils.js
+++ b/lib/keyserver-conn/keyserver-call-utils.js
@@ -5,20 +5,28 @@
 import type { CalendarQuery } from '../types/entry-types.js';
 import type { NotDeletedFilter } from '../types/filter-types.js';
 
-function extractKeyserverIDFromID(id: string): ?string {
+function extractKeyserverIDFromIDOptional(id: string): ?string {
   if (!id.includes('|')) {
     return null;
   }
   return id.split('|')[0];
 }
 
+function extractKeyserverIDFromID(id: string): string {
+  const keyserverID = extractKeyserverIDFromIDOptional(id);
+  invariant(keyserverID, 'Keyserver ID should be present');
+  return keyserverID;
+}
+
 function sortThreadIDsPerKeyserver(threadIDs: $ReadOnlyArray<string>): {
   +[keyserverID: string]: $ReadOnlyArray<string>,
 } {
   const results: { [string]: string[] } = {};
   for (const threadID of threadIDs) {
-    const optionalKeyserverID = extractKeyserverIDFromID(threadID);
-    invariant(optionalKeyserverID, 'keyserver data missing from thread id');
+    const optionalKeyserverID = extractKeyserverIDFromIDOptional(threadID);
+    if (!optionalKeyserverID) {
+      continue;
+    }
     const keyserverID: string = optionalKeyserverID;
     if (results[keyserverID] === undefined) {
       results[keyserverID] = [];
@@ -99,12 +107,13 @@
   }
   const keyserverIDsSet = new Set<string>(keyserverIDs);
   return threadIDs.filter(threadID => {
-    const keyserverID = extractKeyserverIDFromID(threadID);
+    const keyserverID = extractKeyserverIDFromIDOptional(threadID);
     return keyserverID && keyserverIDsSet.has(keyserverID);
   });
 }
 
 export {
+  extractKeyserverIDFromIDOptional,
   extractKeyserverIDFromID,
   sortThreadIDsPerKeyserver,
   sortCalendarQueryPerKeyserver,
diff --git a/lib/keyserver-conn/keyserver-call-utils.test.js b/lib/keyserver-conn/keyserver-call-utils.test.js
--- a/lib/keyserver-conn/keyserver-call-utils.test.js
+++ b/lib/keyserver-conn/keyserver-call-utils.test.js
@@ -4,6 +4,7 @@
   extractKeyserverIDFromID,
   sortCalendarQueryPerKeyserver,
   getThreadIDsForKeyservers,
+  extractKeyserverIDFromIDOptional,
 } from './keyserver-call-utils.js';
 import type { CalendarQuery } from '../types/entry-types';
 
@@ -14,9 +15,22 @@
     expect(extractKeyserverIDFromID(id)).toBe(keyserverID);
   });
 
+  it('should throw for non-keyserver ID', () => {
+    const id = '404';
+    expect(() => extractKeyserverIDFromID(id)).toThrow();
+  });
+});
+
+describe('extractKeyserverIDFromIDOptional', () => {
+  it('should return <keyserverID> for <keyserverID>|<number>', () => {
+    const keyserverID = '404';
+    const id = keyserverID + '|1234';
+    expect(extractKeyserverIDFromIDOptional(id)).toBe(keyserverID);
+  });
+
   it('should return null for non-keyserver ID', () => {
     const id = '404';
-    expect(extractKeyserverIDFromID(id)).toBe(null);
+    expect(extractKeyserverIDFromIDOptional(id)).toBe(null);
   });
 });
 
diff --git a/lib/reducers/calendar-filters-reducer.js b/lib/reducers/calendar-filters-reducer.js
--- a/lib/reducers/calendar-filters-reducer.js
+++ b/lib/reducers/calendar-filters-reducer.js
@@ -18,7 +18,7 @@
   legacyLogInActionTypes,
   legacyKeyserverRegisterActionTypes,
 } from '../actions/user-actions.js';
-import { extractKeyserverIDFromID } from '../keyserver-conn/keyserver-call-utils.js';
+import { extractKeyserverIDFromIDOptional } from '../keyserver-conn/keyserver-call-utils.js';
 import { setNewSessionActionType } from '../keyserver-conn/keyserver-conn-types.js';
 import {
   filteredThreadIDs,
@@ -221,7 +221,7 @@
 ): $ReadOnlyArray<CalendarFilter> {
   const keyserverIDsSet = new Set<string>(keyserverIDs);
   const filterCondition = (threadID: string) => {
-    const keyserverID = extractKeyserverIDFromID(threadID);
+    const keyserverID = extractKeyserverIDFromIDOptional(threadID);
     return !keyserverID || !keyserverIDsSet.has(keyserverID);
   };
 
diff --git a/lib/reducers/draft-reducer.js b/lib/reducers/draft-reducer.js
--- a/lib/reducers/draft-reducer.js
+++ b/lib/reducers/draft-reducer.js
@@ -6,7 +6,7 @@
   updateDraftActionType,
 } from '../actions/draft-actions.js';
 import { deleteKeyserverAccountActionTypes } from '../actions/user-actions.js';
-import { extractKeyserverIDFromID } from '../keyserver-conn/keyserver-call-utils.js';
+import { extractKeyserverIDFromIDOptional } from '../keyserver-conn/keyserver-call-utils.js';
 import { setNewSessionActionType } from '../keyserver-conn/keyserver-conn-types.js';
 import type { DraftStore, DraftStoreOperation } from '../types/draft-types.js';
 import type { BaseAction } from '../types/redux-types.js';
@@ -25,7 +25,7 @@
   const drafts: { [key: string]: string } = {};
   const ids: string[] = [];
   for (const key in draftStore.drafts) {
-    const keyserverID = extractKeyserverIDFromID(key);
+    const keyserverID = extractKeyserverIDFromIDOptional(key);
     if (keyserverID && keyserverIDsSet.has(keyserverID)) {
       ids.push(key);
     } else {
diff --git a/lib/reducers/invite-links-reducer.js b/lib/reducers/invite-links-reducer.js
--- a/lib/reducers/invite-links-reducer.js
+++ b/lib/reducers/invite-links-reducer.js
@@ -6,7 +6,7 @@
   fetchPrimaryInviteLinkActionTypes,
 } from '../actions/link-actions.js';
 import { deleteKeyserverAccountActionTypes } from '../actions/user-actions.js';
-import { extractKeyserverIDFromID } from '../keyserver-conn/keyserver-call-utils.js';
+import { extractKeyserverIDFromIDOptional } from '../keyserver-conn/keyserver-call-utils.js';
 import { setNewSessionActionType } from '../keyserver-conn/keyserver-conn-types.js';
 import type { InviteLinksStore, CommunityLinks } from '../types/link-types.js';
 import type { BaseAction } from '../types/redux-types.js';
@@ -60,7 +60,7 @@
     const keyserverIDsSet = new Set<string>(action.payload.keyserverIDs);
     const newLinks: { [communityID: string]: CommunityLinks } = {};
     for (const linkID in state.links) {
-      const keyserverID = extractKeyserverIDFromID(linkID);
+      const keyserverID = extractKeyserverIDFromIDOptional(linkID);
       if (!keyserverID || !keyserverIDsSet.has(keyserverID)) {
         newLinks[linkID] = state.links[linkID];
       }
@@ -76,7 +76,7 @@
     const { keyserverID } = action.payload;
     const newLinks: { [communityID: string]: CommunityLinks } = {};
     for (const linkID in state.links) {
-      if (extractKeyserverIDFromID(linkID) !== keyserverID) {
+      if (extractKeyserverIDFromIDOptional(linkID) !== keyserverID) {
         newLinks[linkID] = state.links[linkID];
       }
     }
diff --git a/lib/reducers/thread-activity-reducer.js b/lib/reducers/thread-activity-reducer.js
--- a/lib/reducers/thread-activity-reducer.js
+++ b/lib/reducers/thread-activity-reducer.js
@@ -17,7 +17,7 @@
 } from '../actions/thread-actions.js';
 import { fetchPendingUpdatesActionTypes } from '../actions/update-actions.js';
 import { deleteKeyserverAccountActionTypes } from '../actions/user-actions.js';
-import { extractKeyserverIDFromID } from '../keyserver-conn/keyserver-call-utils.js';
+import { extractKeyserverIDFromIDOptional } from '../keyserver-conn/keyserver-call-utils.js';
 import { setNewSessionActionType } from '../keyserver-conn/keyserver-conn-types.js';
 import {
   threadActivityStoreOpsHandlers,
@@ -183,7 +183,7 @@
     const keyserverIDsSet = new Set<string>(action.payload.keyserverIDs);
 
     for (const threadID in state) {
-      const keyserverID = extractKeyserverIDFromID(threadID);
+      const keyserverID = extractKeyserverIDFromIDOptional(threadID);
       if (!keyserverID || !keyserverIDsSet.has(keyserverID)) {
         continue;
       }
@@ -209,7 +209,7 @@
     const { keyserverID } = action.payload;
 
     for (const threadID in state) {
-      if (extractKeyserverIDFromID(threadID) !== keyserverID) {
+      if (extractKeyserverIDFromIDOptional(threadID) !== keyserverID) {
         continue;
       }
       threadIDsToRemove.push(threadID);
diff --git a/lib/shared/message-utils.js b/lib/shared/message-utils.js
--- a/lib/shared/message-utils.js
+++ b/lib/shared/message-utils.js
@@ -11,7 +11,7 @@
 import { messageSpecs } from './messages/message-specs.js';
 import { threadIsGroupChat } from './thread-utils.js';
 import { useStringForUser } from '../hooks/ens-cache.js';
-import { extractKeyserverIDFromID } from '../keyserver-conn/keyserver-call-utils.js';
+import { extractKeyserverIDFromIDOptional } from '../keyserver-conn/keyserver-call-utils.js';
 import { contentStringForMediaArray } from '../media/media-utils.js';
 import type { ChatMessageInfoItem } from '../selectors/chat-selectors.js';
 import { threadInfoSelector } from '../selectors/thread-selectors.js';
@@ -661,7 +661,7 @@
   const timePerKeyserver: { [keyserverID: string]: number } = {};
 
   for (const messageInfo of messageInfos) {
-    const keyserverID = extractKeyserverIDFromID(messageInfo.threadID);
+    const keyserverID = extractKeyserverIDFromIDOptional(messageInfo.threadID);
 
     if (
       keyserverID &&
diff --git a/native/calendar/entry.react.js b/native/calendar/entry.react.js
--- a/native/calendar/entry.react.js
+++ b/native/calendar/entry.react.js
@@ -26,7 +26,7 @@
   useDeleteEntry,
   useSaveEntry,
 } from 'lib/actions/entry-actions.js';
-import { extractKeyserverIDFromID } from 'lib/keyserver-conn/keyserver-call-utils.js';
+import { extractKeyserverIDFromIDOptional } from 'lib/keyserver-conn/keyserver-call-utils.js';
 import { registerFetchKey } from 'lib/reducers/loading-reducer.js';
 import { connectionSelector } from 'lib/selectors/keyserver-selectors.js';
 import { colorIsDark } from 'lib/shared/color-utils.js';
@@ -809,7 +809,7 @@
     const { threadInfo: unresolvedThreadInfo, ...restProps } = props;
     const threadInfo = useResolvedThreadInfo(unresolvedThreadInfo);
 
-    const keyserverID = extractKeyserverIDFromID(threadInfo.id);
+    const keyserverID = extractKeyserverIDFromIDOptional(threadInfo.id);
     const connection = useSelector(state => {
       if (!keyserverID) {
         return {
diff --git a/native/chat/settings/thread-settings-push-notifs.react.js b/native/chat/settings/thread-settings-push-notifs.react.js
--- a/native/chat/settings/thread-settings-push-notifs.react.js
+++ b/native/chat/settings/thread-settings-push-notifs.react.js
@@ -8,7 +8,7 @@
   updateSubscriptionActionTypes,
   useUpdateSubscription,
 } from 'lib/actions/user-actions.js';
-import { extractKeyserverIDFromID } from 'lib/keyserver-conn/keyserver-call-utils.js';
+import { extractKeyserverIDFromIDOptional } from 'lib/keyserver-conn/keyserver-call-utils.js';
 import { deviceTokenSelector } from 'lib/selectors/keyserver-selectors.js';
 import type { ThreadInfo } from 'lib/types/minimally-encoded-thread-permissions-types.js';
 import type {
@@ -175,7 +175,7 @@
   React.memo<BaseProps>(function ConnectedThreadSettingsPushNotifs(
     props: BaseProps,
   ) {
-    const keyserverID = extractKeyserverIDFromID(props.threadInfo.id);
+    const keyserverID = extractKeyserverIDFromIDOptional(props.threadInfo.id);
     const deviceToken = useSelector(state => {
       if (!keyserverID) {
         return state.tunnelbrokerDeviceToken;
diff --git a/native/components/auto-join-community-handler.react.js b/native/components/auto-join-community-handler.react.js
--- a/native/components/auto-join-community-handler.react.js
+++ b/native/components/auto-join-community-handler.react.js
@@ -9,7 +9,7 @@
 } from 'lib/actions/thread-actions.js';
 import { NeynarClientContext } from 'lib/components/neynar-client-provider.react.js';
 import blobService from 'lib/facts/blob-service.js';
-import { extractKeyserverIDFromID } from 'lib/keyserver-conn/keyserver-call-utils.js';
+import { extractKeyserverIDFromIDOptional } from 'lib/keyserver-conn/keyserver-call-utils.js';
 import { cookieSelector } from 'lib/selectors/keyserver-selectors.js';
 import { farcasterChannelTagBlobHash } from 'lib/shared/community-utils.js';
 import type { AuthMetadata } from 'lib/shared/identity-client-context.js';
@@ -126,7 +126,7 @@
         }
 
         const { commCommunityID } = await blobResult.json();
-        const keyserverID = extractKeyserverIDFromID(commCommunityID);
+        const keyserverID = extractKeyserverIDFromIDOptional(commCommunityID);
 
         if (!keyserverID || !keyserverInfos[keyserverID]) {
           return;
diff --git a/native/push/push-handler.react.js b/native/push/push-handler.react.js
--- a/native/push/push-handler.react.js
+++ b/native/push/push-handler.react.js
@@ -1,7 +1,6 @@
 // @flow
 
 import * as Haptics from 'expo-haptics';
-import invariant from 'invariant';
 import _groupBy from 'lodash/fp/groupBy.js';
 import * as React from 'react';
 import { LogBox, Platform } from 'react-native';
@@ -756,7 +755,6 @@
     this.saveMessageInfos(messageInfos);
 
     const keyserverID = extractKeyserverIDFromID(message.threadID);
-    invariant(keyserverID, 'Keyserver ID should be present');
     const updateCurrentAsOf = this.props.allUpdatesCurrentAsOf[keyserverID];
 
     handleAndroidMessage(
diff --git a/web/calendar/entry.react.js b/web/calendar/entry.react.js
--- a/web/calendar/entry.react.js
+++ b/web/calendar/entry.react.js
@@ -474,19 +474,12 @@
     );
     const calendarQuery = useSelector(nonThreadCalendarQuery);
     const keyserverID = extractKeyserverIDFromID(threadID);
-    const connection = useSelector(state => {
+    const online = useSelector(state => {
       if (!keyserverID) {
-        return {
-          status: 'connected',
-        };
+        return true;
       }
-      return connectionSelector(keyserverID)(state);
+      return connectionSelector(keyserverID)(state) === 'connected';
     });
-    invariant(
-      connection,
-      `keyserver ${keyserverID ?? 'null'} missing from keyserverStore`,
-    );
-    const online = connection.status === 'connected';
     const callCreateEntry = useCreateEntry();
     const callSaveEntry = useSaveEntry();
     const callDeleteEntry = useDeleteEntry();