As part of learning python and asyncio I have a simple TCP client/server architecture using asyncio (I have reasons why I need to use that) where I want the server to completely exit when it receives the string 'quit' from the client. The server, stored in asyncio_server.py, looks like this: import socket import asyncio class Server: def __init__(self, host, port): self.host = host self.port = port async def handle_client(self, reader, writer): # Callback from asyncio.start_server() when # a client tries to establish a connection addr = writer.get_extra_info('peername') print(f'Accepted connection from {addr!r}') request = None try: while request != 'quit': request = (await reader.read(255)).decode('utf8') print(f"Received {request!r} from {addr!r}") response = 'ok' writer.write(response.encode('utf8')) await writer.drain() print(f'Sent {response!r} to {addr!r}') print('----------') except Exception as e: print(f"Error handling client {addr!r}: {e}") finally: print(f"Connection closed by {addr!r}") writer.close() await writer.wait_closed() print(f'Closed the connection with {addr!r}') asyncio.get_event_loop().stop() # <<< WHAT SHOULD THIS BE? async def start(self): server = await asyncio.start_server(self.handle_client, self.host, self.port) async with server: print(f"Serving on {self.host}:{self.port}") await server.serve_forever() async def main(): server = Server(socket.gethostname(), 5000) await server.start() if __name__ == '__main__': asyncio.run(main()) and when the client sends quit the connection is closed and the server exits but always with the error message: Traceback (most recent call last): File "asyncio_server.py", line 54, in <module> asyncio.run(main()) File "C:\Python38-32\lib\asyncio\runners.py", line 44, in run return loop.run_until_complete(main) File "C:\Python38-32\lib\asyncio\base_events.py", line 614, in run_until_complete raise RuntimeError('Event loop stopped before Future completed.') RuntimeError: Event loop stopped before Future completed. What do I need to do instead of or in addition to calling asyncio.get_event_loop().stop() and/or server.serve_forever() to have the server exit gracefully with no error messages? I've tried every alternative I can find with google, including calling cancel() on the server, using separate loop construct in main(), trying alternatives to stop(), alternatives to run_forever(), etc., etc. and cannot figure out what I'm supposed to do to gracefully stop the server and exit the program without error messages when it receives a quit message from the client. I'm using python 3.8.10 and cannot upgrade to a newer version due to managed environment constraints. I'm also calling python from git bash in case that matters. Additional Information: The client code, stored in asyncio_client.py`, is below in case that's useful. import socket import asyncio class Client: def __init__(self, host, port): self.host = host self.port = port async def handle_server(self, reader, writer): addr = writer.get_extra_info('peername') print(f'Connected to from {addr!r}') request = input('Enter Request: ') while request.lower().strip() != 'quit': writer.write(request.encode()) await writer.drain() print(f'Sent {request!r} to {addr!r}') response = await reader.read(1024) print(f'Received {response.decode()!r} from {addr!r}') print('----------') request = input('Enter Request: ') writer.write(request.encode()) await writer.drain() print(f'Sent {request!r} to {addr!r}') writer.close() await writer.wait_closed() print(f'Closed the connection with {addr!r}') async def start(self): reader, writer = await asyncio.open_connection(host=self.host, port=self.port) await self.handle_server(reader, writer) async def main(): client = Client(socket.gethostname(), 5000) await client.start() if __name__ == '__main__': asyncio.run(main()) Continue reading...