# Buggy code
def _invalidate_get_users_with_receipts_in_room(self, room_id, receipt_type, user_id):
    if receipt_type != "m.read":
        return

    # Returns an ObservableDeferred
    res = self.get_users_with_read_receipts_in_room.cache.get(
        room_id,
        None,
        update_metrics=False,
    )

    if res:
        if isinstance(res, defer.Deferred) and res.called:
            res = res.result
        if user_id in res:
            # We'd only be adding to the set, so no point invalidating if the
            # user is already there
            return

    self.get_users_with_read_receipts_in_room.invalidate((room_id,))


# Traceback (TypeError)
homeserver - 2018-05-18 00:40:04,123 - synapse.federation.federation_server - 643 - ERROR - Failed to handle edu 'm.receipt'
Traceback (most recent call last):
File "/home/matrix/.synapse/local/lib/python2.7/site-packages/synapse/federation/federation_server.py", line 639, in on_edu
yield handler(origin, content)
File "/home/matrix/.synapse/local/lib/python2.7/site-packages/twisted/internet/defer.py", line 1384, in _inlineCallbacks
result = result.throwExceptionIntoGenerator(g)
File "/home/matrix/.synapse/local/lib/python2.7/site-packages/twisted/python/failure.py", line 422, in throwExceptionIntoGenerator
return g.throw(self.type, self.value, self.tb)
File "/home/matrix/.synapse/local/lib/python2.7/site-packages/synapse/handlers/receipts.py", line 84, in _received_remote_receipt
yield self._handle_new_receipts(receipts)
File "/home/matrix/.synapse/local/lib/python2.7/site-packages/twisted/internet/defer.py", line 1384, in _inlineCallbacks
result = result.throwExceptionIntoGenerator(g)
File "/home/matrix/.synapse/local/lib/python2.7/site-packages/twisted/python/failure.py", line 422, in throwExceptionIntoGenerator
return g.throw(self.type, self.value, self.tb)
File "/home/matrix/.synapse/local/lib/python2.7/site-packages/synapse/handlers/receipts.py", line 101, in _handle_new_receipts
room_id, receipt_type, user_id, event_ids, data
File "/home/matrix/.synapse/local/lib/python2.7/site-packages/twisted/internet/defer.py", line 1384, in _inlineCallbacks
result = result.throwExceptionIntoGenerator(g)
File "/home/matrix/.synapse/local/lib/python2.7/site-packages/twisted/python/failure.py", line 422, in throwExceptionIntoGenerator
return g.throw(self.type, self.value, self.tb)
File "/home/matrix/.synapse/local/lib/python2.7/site-packages/synapse/storage/receipts.py", line 456, in insert_receipt
stream_id=stream_id,
File "/home/matrix/.synapse/local/lib/python2.7/site-packages/twisted/internet/defer.py", line 1386, in _inlineCallbacks
result = g.send(result)
File "/home/matrix/.synapse/local/lib/python2.7/site-packages/synapse/storage/_base.py", line 323, in runInteraction
after_callback(*after_args, **after_kwargs)
File "/home/matrix/.synapse/local/lib/python2.7/site-packages/synapse/storage/receipts.py", line 308, in _invalidate_get_users_with_receipts_in_room
if user_id in res:
TypeError: argument of type 'ObservableDeferred' is not iterable

# Fixed code
def _invalidate_get_users_with_receipts_in_room(self, room_id, receipt_type, user_id):
    if receipt_type != "m.read":
        return

    # Returns either an ObservableDeferred or the raw result
    res = self.get_users_with_read_receipts_in_room.cache.get(
        room_id,
        None,
        update_metrics=False,
    )

    # first handle the Deferred case
    if isinstance(res, defer.Deferred):
        if res.called:
            res = res.result
        else:
            res = None

    if res and user_id in res:
        # We'd only be adding to the set, so no point invalidating if the
        # user is already there
        return

    self.get_users_with_read_receipts_in_room.invalidate((room_id,))