diff --git a/keyserver/src/creators/update-creator.js b/keyserver/src/creators/update-creator.js
--- a/keyserver/src/creators/update-creator.js
+++ b/keyserver/src/creators/update-creator.js
@@ -481,9 +481,10 @@
   }
 
   if (entryIDsNeedingFetch.size > 0) {
-    promises.entryInfosResult = fetchEntryInfosByID(viewer, [
-      ...entryIDsNeedingFetch,
-    ]);
+    promises.entryInfosResult = fetchEntryInfosByID(
+      viewer,
+      entryIDsNeedingFetch,
+    );
   }
 
   if (currentUserNeedsFetch) {
diff --git a/keyserver/src/fetchers/entry-fetchers.js b/keyserver/src/fetchers/entry-fetchers.js
--- a/keyserver/src/fetchers/entry-fetchers.js
+++ b/keyserver/src/fetchers/entry-fetchers.js
@@ -37,7 +37,7 @@
   viewer: Viewer,
   entryID: string,
 ): Promise<?RawEntryInfo> {
-  const results = await fetchEntryInfosByID(viewer, [entryID]);
+  const results = await fetchEntryInfosByID(viewer, new Set([entryID]));
   if (results.length === 0) {
     return null;
   }
@@ -61,9 +61,9 @@
 const visPermissionExtractString = `$.${threadPermissions.VISIBLE}.value`;
 async function fetchEntryInfosByID(
   viewer: Viewer,
-  entryIDs: $ReadOnlyArray<string>,
+  entryIDs: $ReadOnlySet<string>,
 ): Promise<RawEntryInfo[]> {
-  if (entryIDs.length === 0) {
+  if (entryIDs.size === 0) {
     return [];
   }
   const viewerID = viewer.id;
@@ -74,7 +74,7 @@
     FROM entries e
     LEFT JOIN days d ON d.id = e.day
     LEFT JOIN memberships m ON m.thread = d.thread AND m.user = ${viewerID}
-    WHERE e.id IN (${entryIDs}) AND
+    WHERE e.id IN (${[...entryIDs]}) AND
       JSON_EXTRACT(m.permissions, ${visPermissionExtractString}) IS TRUE
   `;
   const [result] = await dbQuery(query);
diff --git a/keyserver/src/socket/session-utils.js b/keyserver/src/socket/session-utils.js
--- a/keyserver/src/socket/session-utils.js
+++ b/keyserver/src/socket/session-utils.js
@@ -424,8 +424,8 @@
     fetchAllUserInfos = false,
     fetchUserInfo = false;
   const threadIDsToFetch = new Set(),
-    entryIDsToFetch = [],
-    userIDsToFetch = [];
+    entryIDsToFetch = new Set(),
+    userIDsToFetch = new Set();
   for (const key of invalidKeys) {
     if (key === 'threadInfos') {
       fetchAllThreads = true;
@@ -440,10 +440,10 @@
       threadIDsToFetch.add(threadID);
     } else if (key.startsWith('entryInfo|')) {
       const [, entryID] = key.split('|');
-      entryIDsToFetch.push(entryID);
+      entryIDsToFetch.add(entryID);
     } else if (key.startsWith('userInfo|')) {
       const [, userID] = key.split('|');
-      userIDsToFetch.push(userID);
+      userIDsToFetch.add(userID);
     }
   }
 
@@ -457,13 +457,13 @@
   }
   if (fetchAllEntries) {
     fetchPromises.entriesResult = fetchEntryInfos(viewer, [calendarQuery]);
-  } else if (entryIDsToFetch.length > 0) {
+  } else if (entryIDsToFetch.size > 0) {
     fetchPromises.entryInfos = fetchEntryInfosByID(viewer, entryIDsToFetch);
   }
   if (fetchAllUserInfos) {
     fetchPromises.userInfos = fetchKnownUserInfos(viewer);
-  } else if (userIDsToFetch.length > 0) {
-    fetchPromises.userInfos = fetchKnownUserInfos(viewer, userIDsToFetch);
+  } else if (userIDsToFetch.size > 0) {
+    fetchPromises.userInfos = fetchKnownUserInfos(viewer, [...userIDsToFetch]);
   }
   if (fetchUserInfo) {
     fetchPromises.currentUserInfo = fetchCurrentUserInfo(viewer);