diff --git a/changelog.d/17727.bugfix b/changelog.d/17727.bugfix
new file mode 100644
index 0000000000000000000000000000000000000000..64c6e90d87e0605b74b5d1d16f7ae483f892df55
--- /dev/null
+++ b/changelog.d/17727.bugfix
@@ -0,0 +1 @@
+Fix a bug in SSS which could prevent /sync from working for certain user accounts.
diff --git a/synapse/storage/databases/main/stream.py b/synapse/storage/databases/main/stream.py
index 94a7efee7355c18c9ed8639fc04bb24063304472..03b4aa33818216b434e0505760349355855e60d7 100644
--- a/synapse/storage/databases/main/stream.py
+++ b/synapse/storage/databases/main/stream.py
@@ -1469,6 +1469,10 @@ class StreamWorkerStore(EventsWorkerStore, SQLBaseStore):
         recheck_rooms: Set[str] = set()
         min_token = end_token.stream
         for room_id, stream in uncapped_results.items():
+            if stream is None:
+                # Despite the function not directly setting None, the cache can!
+                # See: https://github.com/element-hq/synapse/issues/17726
+                continue
             if stream <= min_token:
                 results[room_id] = stream
             else:
@@ -1495,7 +1499,7 @@ class StreamWorkerStore(EventsWorkerStore, SQLBaseStore):
     @cachedList(cached_method_name="_get_max_event_pos", list_name="room_ids")
     async def _bulk_get_max_event_pos(
         self, room_ids: StrCollection
-    ) -> Mapping[str, int]:
+    ) -> Mapping[str, Optional[int]]:
         """Fetch the max position of a persisted event in the room."""
 
         # We need to be careful not to return positions ahead of the current