diff --git a/lib/hooks/thread-time.js b/lib/hooks/thread-time.js
--- a/lib/hooks/thread-time.js
+++ b/lib/hooks/thread-time.js
@@ -28,17 +28,30 @@
       //   lastUpdatedTime promises until we have N items that after resolving
       //   lastUpdatedTime, have higher values than any of the other items'
       //   lastUpdatedAtMostTime
-      let lastUpdatedAtLeastTime = threadInfo.creationTime;
 
       const thread = messageStore.threads[threadInfo.id];
-      if (!thread || !viewerID) {
+      if (!thread || !viewerID || thread.messageIDs.length === 0) {
         return {
-          lastUpdatedAtLeastTime,
+          lastUpdatedAtLeastTime: threadInfo.creationTime,
           lastUpdatedAtMostTime: threadInfo.creationTime,
           lastUpdatedTime: () => Promise.resolve(threadInfo.creationTime),
         };
       }
 
+      // We default to the most recent message time.
+      // - This default will only be relevant in the case that
+      //   getLastUpdatedTime is implemented for every message in the loop
+      //   below, and doesn't return a number for any of them. Otherwise
+      //   lastUpdatedAtLeastTime will be set to the most recent message that
+      //   returns a number, or whose message spec doesn't implement
+      //   getLastUpdatedTime.
+      // - We default to the most recent message time because the best
+      //   alternative is the thread creation time, but this is likely very
+      //   far in the past.
+      const mostRecentMessage = messageStore.messages[thread.messageIDs[0]];
+      let lastUpdatedAtLeastTime =
+        mostRecentMessage?.time ?? threadInfo.creationTime;
+
       const getLastUpdatedTimeParams = {
         threadInfo,
         viewerID,