{"record":{"id":"02c8345045870ad7","repo":"microsoft/autogen","slug":"connection-is-not-open","errorCode":null,"errorMessage":"Connection is not open.","messagePattern":"Connection is not open\\.","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"python/packages/autogen-ext/src/autogen_ext/runtimes/grpc/_worker_runtime.py","lineNumber":159,"sourceCode":"            (k, v) for k, v in {**dict(HostConnection.DEFAULT_GRPC_CONFIG), **dict(extra_grpc_config)}.items()\n        ]\n\n        channel = grpc.aio.insecure_channel(\n            host_address,\n            options=merged_options,\n        )\n        stub: AgentRpcAsyncStub = agent_worker_pb2_grpc.AgentRpcStub(channel)  # type: ignore\n        instance = cls(channel, stub)\n\n        instance._connection_task = await instance._connect(\n            stub, instance._send_queue, instance._recv_queue, instance._client_id\n        )\n\n        return instance\n\n    async def close(self) -> None:\n        if self._connection_task is None:\n            raise RuntimeError(\"Connection is not open.\")\n        await self._channel.close()\n        await self._connection_task\n\n    @staticmethod\n    async def _connect(\n        stub: Any,  # AgentRpcAsyncStub\n        send_queue: asyncio.Queue[agent_worker_pb2.Message],\n        receive_queue: asyncio.Queue[agent_worker_pb2.Message],\n        client_id: str,\n    ) -> Task[None]:\n        from grpc.aio import StreamStreamCall\n\n        # TODO: where do exceptions from reading the iterable go? How do we recover from those?\n        stream: StreamStreamCall[agent_worker_pb2.Message, agent_worker_pb2.Message] = stub.OpenChannel(  # type: ignore\n            QueueAsyncIterable(send_queue), metadata=[(\"client-id\", client_id)]\n        )\n\n        await stream.wait_for_connection()","sourceCodeStart":141,"sourceCodeEnd":177,"githubUrl":"https://github.com/microsoft/autogen/blob/027ecf0a379bcc1d09956d46d12d44a3ad9cee14/python/packages/autogen-ext/src/autogen_ext/runtimes/grpc/_worker_runtime.py#L141-L177","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"# before\nconn = None\ntry:\n    conn = await SomeCls.connect(...)\nfinally:\n    await conn.close()  # RuntimeError if connect failed\n\n# after\nfinally:\n    if conn is not None:\n        await conn.close()","handlingStrategy":"try-catch","validationCode":"def can_close(conn) -> bool:\n    return getattr(conn, \"_connection_task\", None) is not None","typeGuard":null,"tryCatchPattern":"try:\n    await conn.close()\nexcept RuntimeError as e:\n    if \"Connection is not open\" in str(e):\n        pass  # nothing to close\n    else:\n        raise","preventionTips":["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"],"tags":["python","autogen","grpc","lifecycle","connection-management"],"backgroundTag":null,"analyzedSha":"027ecf0a379bcc1d09956d46d12d44a3ad9cee14","analyzedAt":"2026-08-15T03:38:00.719Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}