# Buggy code
async def received_message(self, msg):
    self._dispatch("socket_raw_receive", msg)

    if type(msg) is bytes:
        self._buffer.extend(msg)

        if len(msg) >= 4:
            if msg[-4:] == b"\x00\x00\xff\xff":
                msg = self._zlib.decompress(self._buffer)
                msg = msg.decode("utf-8")
                self._buffer = bytearray()
            else:
                return
        else:
            return

    msg = json.loads(msg)

    log.debug("For Shard ID %s: WebSocket Event: %s", self.shard_id, msg)
    self._dispatch("socket_response", msg)

    op = msg.get("op")
    data = msg.get("d")
    seq = msg.get("s")
    if seq is not None:
        self.sequence = seq

    if op != self.DISPATCH:
        if op == self.RECONNECT:
            # "reconnect" can only be handled by the Client
            # so we terminate our connection and raise an
            # internal exception signalling to reconnect.
            log.debug("Received RECONNECT opcode.")
            await self.close()
            raise ReconnectWebSocket(self.shard_id)

        if op == self.HEARTBEAT_ACK:
            self._keep_alive.ack()
            return

        if op == self.HEARTBEAT:
            beat = self._keep_alive.get_payload()
            await self.send_as_json(beat)
            return

        if op == self.HELLO:
            interval = data["heartbeat_interval"] / 1000.0
            self._keep_alive = KeepAliveHandler(
                ws=self, interval=interval, shard_id=self.shard_id
            )
            # send a heartbeat immediately
            await self.send_as_json(self._keep_alive.get_payload())
            self._keep_alive.start()
            return

        if op == self.INVALIDATE_SESSION:
            if data is True:
                await self.close()
                raise ReconnectWebSocket(self.shard_id)

            self.sequence = None
            self.session_id = None
            log.info("Shard ID %s session has been invalidated.", self.shard_id)
            await self.close(code=1000)
            raise ReconnectWebSocket(self.shard_id, resume=False)

        log.warning("Unknown OP code %s.", op)
        return

    event = msg.get("t")

    if event == "READY":
        self._trace = trace = data.get("_trace", [])
        self.sequence = msg["s"]
        self.session_id = data["session_id"]
        # pass back shard ID to ready handler
        data["__shard_id__"] = self.shard_id
        log.info(
            "Shard ID %s has connected to Gateway: %s (Session ID: %s).",
            self.shard_id,
            ", ".join(trace),
            self.session_id,
        )

    elif event == "RESUMED":
        self._trace = trace = data.get("_trace", [])
        # pass back the shard ID to the resumed handler
        data["__shard_id__"] = self.shard_id
        log.info(
            "Shard ID %s has successfully RESUMED session %s under trace %s.",
            self.shard_id,
            self.session_id,
            ", ".join(trace),
        )

    try:
        func = self._discord_parsers[event]
    except KeyError:
        log.debug("Unknown event %s.", event)
    else:
        func(data)

    # remove the dispatched listeners
    removed = []
    for index, entry in enumerate(self._dispatch_listeners):
        if entry.event != event:
            continue

        future = entry.future
        if future.cancelled():
            removed.append(index)
            continue

        try:
            valid = entry.predicate(data)
        except Exception as exc:
            future.set_exception(exc)
            removed.append(index)
        else:
            if valid:
                ret = data if entry.result is None else entry.result(data)
                future.set_result(ret)
                removed.append(index)

    for index in reversed(removed):
        del self._dispatch_listeners[index]


# Traceback (AttributeError)
2020-09-08 09:18:22   -   ready to go...

Traceback (most recent call last):
File "voicemaster.py", line 264, in <module>
bot.run(bot_token)
File "/usr/local/lib/python3.6/dist-packages/discord/client.py", line 678, in run
return future.result()
File "/usr/local/lib/python3.6/dist-packages/discord/client.py", line 658, in runner
await self.start(*args, **kwargs)
File "/usr/local/lib/python3.6/dist-packages/discord/client.py", line 622, in start
await self.connect(reconnect=reconnect)
File "/usr/local/lib/python3.6/dist-packages/discord/shard.py", line 414, in connect
raise item.error
File "/usr/local/lib/python3.6/dist-packages/discord/shard.py", line 140, in worker
await self.ws.poll_event()
File "/usr/local/lib/python3.6/dist-packages/discord/gateway.py", line 504, in poll_event
await self.received_message(msg.data)
File "/usr/local/lib/python3.6/dist-packages/discord/gateway.py", line 401, in received_message
self._keep_alive.ack()
AttributeError: 'NoneType' object has no attribute 'ack'
Unclosed client session
client_session: <aiohttp.client.ClientSession object at 0x7f88a6110828>

# Fixed code
async def received_message(self, msg):
    self._dispatch("socket_raw_receive", msg)

    if type(msg) is bytes:
        self._buffer.extend(msg)

        if len(msg) >= 4:
            if msg[-4:] == b"\x00\x00\xff\xff":
                msg = self._zlib.decompress(self._buffer)
                msg = msg.decode("utf-8")
                self._buffer = bytearray()
            else:
                return
        else:
            return

    msg = json.loads(msg)

    log.debug("For Shard ID %s: WebSocket Event: %s", self.shard_id, msg)
    self._dispatch("socket_response", msg)

    op = msg.get("op")
    data = msg.get("d")
    seq = msg.get("s")
    if seq is not None:
        self.sequence = seq

    if op != self.DISPATCH:
        if op == self.RECONNECT:
            # "reconnect" can only be handled by the Client
            # so we terminate our connection and raise an
            # internal exception signalling to reconnect.
            log.debug("Received RECONNECT opcode.")
            await self.close()
            raise ReconnectWebSocket(self.shard_id)

        if op == self.HEARTBEAT_ACK:
            if self._keep_alive:
                self._keep_alive.ack()
            return

        if op == self.HEARTBEAT:
            if self._keep_alive:
                beat = self._keep_alive.get_payload()
                await self.send_as_json(beat)
            return

        if op == self.HELLO:
            interval = data["heartbeat_interval"] / 1000.0
            self._keep_alive = KeepAliveHandler(
                ws=self, interval=interval, shard_id=self.shard_id
            )
            # send a heartbeat immediately
            await self.send_as_json(self._keep_alive.get_payload())
            self._keep_alive.start()
            return

        if op == self.INVALIDATE_SESSION:
            if data is True:
                await self.close()
                raise ReconnectWebSocket(self.shard_id)

            self.sequence = None
            self.session_id = None
            log.info("Shard ID %s session has been invalidated.", self.shard_id)
            await self.close(code=1000)
            raise ReconnectWebSocket(self.shard_id, resume=False)

        log.warning("Unknown OP code %s.", op)
        return

    event = msg.get("t")

    if event == "READY":
        self._trace = trace = data.get("_trace", [])
        self.sequence = msg["s"]
        self.session_id = data["session_id"]
        # pass back shard ID to ready handler
        data["__shard_id__"] = self.shard_id
        log.info(
            "Shard ID %s has connected to Gateway: %s (Session ID: %s).",
            self.shard_id,
            ", ".join(trace),
            self.session_id,
        )

    elif event == "RESUMED":
        self._trace = trace = data.get("_trace", [])
        # pass back the shard ID to the resumed handler
        data["__shard_id__"] = self.shard_id
        log.info(
            "Shard ID %s has successfully RESUMED session %s under trace %s.",
            self.shard_id,
            self.session_id,
            ", ".join(trace),
        )

    try:
        func = self._discord_parsers[event]
    except KeyError:
        log.debug("Unknown event %s.", event)
    else:
        func(data)

    # remove the dispatched listeners
    removed = []
    for index, entry in enumerate(self._dispatch_listeners):
        if entry.event != event:
            continue

        future = entry.future
        if future.cancelled():
            removed.append(index)
            continue

        try:
            valid = entry.predicate(data)
        except Exception as exc:
            future.set_exception(exc)
            removed.append(index)
        else:
            if valid:
                ret = data if entry.result is None else entry.result(data)
                future.set_result(ret)
                removed.append(index)

    for index in reversed(removed):
        del self._dispatch_listeners[index]