microsoft/autogen · error · RuntimeError
Connection is not open.
Error message
Connection is not open.
What it means
HostConnection.close() (returned by GrpcWorkerAgentRuntimeHost.connect / from_host_address) requires an active connection task; if _connection_task is None the connection was never opened (or already closed), and close() raises RuntimeError instead of silently succeeding.
Source
Thrown at python/packages/autogen-ext/src/autogen_ext/runtimes/grpc/_worker_runtime.py:159
(k, v) for k, v in {**dict(HostConnection.DEFAULT_GRPC_CONFIG), **dict(extra_grpc_config)}.items()
]
channel = grpc.aio.insecure_channel(
host_address,
options=merged_options,
)
stub: AgentRpcAsyncStub = agent_worker_pb2_grpc.AgentRpcStub(channel) # type: ignore
instance = cls(channel, stub)
instance._connection_task = await instance._connect(
stub, instance._send_queue, instance._recv_queue, instance._client_id
)
return instance
async def close(self) -> None:
if self._connection_task is None:
raise RuntimeError("Connection is not open.")
await self._channel.close()
await self._connection_task
@staticmethod
async def _connect(
stub: Any, # AgentRpcAsyncStub
send_queue: asyncio.Queue[agent_worker_pb2.Message],
receive_queue: asyncio.Queue[agent_worker_pb2.Message],
client_id: str,
) -> Task[None]:
from grpc.aio import StreamStreamCall
# TODO: where do exceptions from reading the iterable go? How do we recover from those?
stream: StreamStreamCall[agent_worker_pb2.Message, agent_worker_pb2.Message] = stub.OpenChannel( # type: ignore
QueueAsyncIterable(send_queue), metadata=[("client-id", client_id)]
)
await stream.wait_for_connection()View on GitHub (pinned to 027ecf0a37)
Solutions
- Only call close() on a fully constructed, successfully opened connection — track whether connect succeeded
- In finally blocks, guard with a None check or try/except RuntimeError
- Use the runtime's own stop()/close() lifecycle instead of managing the raw connection
Example fix
# before
conn = None
try:
conn = await SomeCls.connect(...)
finally:
await conn.close() # RuntimeError if connect failed
# after
finally:
if conn is not None:
await conn.close() Defensive patterns
Strategy: try-catch
Validate before calling
def can_close(conn) -> bool:
return getattr(conn, "_connection_task", None) is not None Try / catch
try:
await conn.close()
except RuntimeError as e:
if "Connection is not open" in str(e):
pass # nothing to close
else:
raise Prevention
- Only close connections you successfully opened
- Use try/finally with a None-initialized handle and None-check before close
- Prefer runtime-level stop()/close() over managing raw HostConnection objects
When it happens
Trigger: Calling `await connection.close()` before ever calling connect()/from_host_address successfully, or calling close() twice (though double-close typically fails differently); in this adapter path, closing a connection whose _connection_task attribute is still None.
Common situations: Error-handling paths that close a connection in a finally block even when setup failed halfway; race where an exception during connect leaves a partially constructed instance that still gets closed.
Related errors
- Runtime is already running.
- Runtime is not running.
- Host connection is not set.
- Runtime must be running when sending message.
- Runtime must be running when publishing message.
AI-assisted analysis of microsoft/autogen@027ecf0a37 (2026-08-15).
Data as JSON: /api/errors/02c8345045870ad7.
Report an issue: GitHub.