Skip to content

asyncio.start_server() leaves the transport open when a synchronous client callback raises #155928

Description

@yangbaechu

Bug report

Bug description:

When a synchronous client_connected_cb passed to asyncio.start_server() raises, the exception is reported by the event loop, but the server-side transport remains open.

import asyncio


async def main():
    loop = asyncio.get_running_loop()
    errors = []
    loop.set_exception_handler(lambda _, ctx: errors.append(ctx))

    connected = loop.create_future()

    def callback(reader, writer):
        connected.set_result(writer.transport)
        raise RuntimeError("boom")

    server = await asyncio.start_server(callback, "127.0.0.1", 0)
    _, client = await asyncio.open_connection(
        *server.sockets[0].getsockname()
    )

    transport = await connected
    print(len(errors), transport.is_closing())  # 1 False

    transport.close()
    client.close()
    server.close()
    await server.wait_closed()


asyncio.run(main())

The exception is reported once, but transport.is_closing() remains False.

Coroutine callbacks already close the transport when their task fails. The synchronous path should provide the same cleanup while preserving the existing exception reporting through Handle._run().

Related: #110894 and PR #111601.

CPython versions tested on:

CPython main branch

Operating systems tested on:

Linux

Linked PRs

Metadata

Metadata

Assignees

No one assigned

    Labels

    stdlibStandard Library Python modules in the Lib/ directorytopic-asynciotype-bugAn unexpected behavior, bug, or error

    Projects

    Status
    Todo

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions