diff --git a/synapse/rest/client/paginated_sync.py b/synapse/rest/client/paginated_sync.py index 4bf54ce8ca..fc81952f39 100644 --- a/synapse/rest/client/paginated_sync.py +++ b/synapse/rest/client/paginated_sync.py @@ -23,7 +23,6 @@ sync servlet; only the request parsing and the top-level response differ. import logging from typing import TYPE_CHECKING -from synapse.api.errors import SynapseError from synapse.http.server import HttpServer from synapse.http.servlet import ( parse_and_validate_json_object_from_request, @@ -81,18 +80,12 @@ class MSC4525PaginatedSyncRestServlet(SlidingSyncRestServlet): from_token = None if from_token_string is not None: - try: - from_token = await SlidingSyncStreamToken.from_string( - self.store, from_token_string - ) - except SynapseError: - # There is no client error path in this API: an unparsable - # `pos` is treated the same as an unrecognised one - as - # absent, so the connection starts afresh. - logger.info( - "Unparsable paginated sync pos for %s; starting the connection afresh", - user, - ) + # A syntactically invalid pos is a plain 400, as elsewhere. Only a + # well-formed pos the server doesn't recognise restarts the + # connection (see the handler). + from_token = await SlidingSyncStreamToken.from_string( + self.store, from_token_string + ) body = parse_and_validate_json_object_from_request( request, MSC4525PaginatedSyncBody diff --git a/tests/rest/client/sliding_sync/test_msc4525_paginated_sync.py b/tests/rest/client/sliding_sync/test_msc4525_paginated_sync.py index 2d00a336ea..7f7f066dd5 100644 --- a/tests/rest/client/sliding_sync/test_msc4525_paginated_sync.py +++ b/tests/rest/client/sliding_sync/test_msc4525_paginated_sync.py @@ -339,9 +339,17 @@ class MSC4525PaginatedSyncTestCase(unittest.HomeserverTestCase): for room_id, room_response in response["rooms"].items(): self.assertTrue(room_response.get("initial"), room_id) - # An entirely unparsable pos is treated the same way, not a 400. - response = self._sync(body, pos="not a token at all") - self.assertEqual(set(response["rooms"].keys()), set(room_ids)) + # A syntactically invalid pos, by contrast, is a plain 400: only + # well-formed-but-unrecognised positions restart the connection. + path = ( + self.sync_endpoint + + "?" + + urllib.parse.urlencode({"timeout": "0", "pos": "not a token at all"}) + ) + channel = self.make_request( + method="POST", path=path, content=body, access_token=self.tok + ) + self.assertEqual(channel.code, 400, channel.json_body) def test_cold_start_backlog_not_starved_by_live_traffic(self) -> None: """Rooms never sent on the connection get a reserved slice of every