microsoft/autogen · error · ValueError

Runtime is already running.

Error message

Runtime is already running.

What it means

GrpcWorkerAgentRuntime.start() is not idempotent: it checks the internal _running flag and raises ValueError('Runtime is already running.') if start() is called again without an intervening stop(). This protects the single read-loop task and host connection from being duplicated.

Source

Thrown at python/packages/autogen-ext/src/autogen_ext/runtimes/grpc/_worker_runtime.py:264

        self._pending_requests: Dict[str, Future[Any]] = {}
        self._pending_requests_lock = asyncio.Lock()
        self._next_request_id = 0
        self._host_connection: HostConnection | None = None
        self._background_tasks: Set[Task[Any]] = set()
        self._subscription_manager = SubscriptionManager()
        self._serialization_registry = SerializationRegistry()
        self._extra_grpc_config = extra_grpc_config or []
        self._agent_instance_types: Dict[str, Type[Agent]] = {}

        if payload_serialization_format not in {JSON_DATA_CONTENT_TYPE, PROTOBUF_DATA_CONTENT_TYPE}:
            raise ValueError(f"Unsupported payload serialization format: {payload_serialization_format}")

        self._payload_serialization_format = payload_serialization_format

    async def start(self) -> None:
        """Start the runtime in a background task."""
        if self._running:
            raise ValueError("Runtime is already running.")
        logger.info(f"Connecting to host: {self._host_address}")
        self._host_connection = await HostConnection.from_host_address(
            self._host_address, extra_grpc_config=self._extra_grpc_config
        )
        logger.info("Connection established")
        if self._read_task is None:
            self._read_task = asyncio.create_task(self._run_read_loop())
        self._running = True

    def _raise_on_exception(self, task: Task[Any]) -> None:
        exception = task.exception()
        if exception is not None:
            raise exception

    async def _run_read_loop(self) -> None:
        logger.info("Starting read loop")
        assert self._host_connection is not None
        # TODO: catch exceptions and reconnect

View on GitHub (pinned to 027ecf0a37)

Solutions

  1. Track started state yourself and only call start() once per lifecycle
  2. Catch/avoid: check runtime state or guard with try/except ValueError if double-start is possible
  3. Call `await runtime.stop()` (and optionally `await runtime.close()`) before restarting in restart loops

Example fix

# before
await runtime.start()  # ValueError on second call

# after
started = False
if not started:
    await runtime.start()
    started = True
Defensive patterns

Strategy: validation

Validate before calling

# start only if not running (track locally; _running is private)
started = False
async def ensure_started(runtime):
    global started
    if not started:
        await runtime.start()
        started = True

Try / catch

try:
    await runtime.start()
except ValueError as e:
    if "already running" in str(e):
        pass  # idempotent start
    else:
        raise

Prevention

When it happens

Trigger: Calling `await runtime.start()` twice, e.g. in a retry wrapper, a Jupyter notebook re-execution, or after a framework (like an agent runtime host) already started the runtime for you.

Common situations: Notebook workflows where a cell is re-run; orchestration code that starts the runtime per-task inside a long-lived process; wrapping start() in a generic retry loop.

Related errors


AI-assisted analysis of microsoft/autogen@027ecf0a37 (2026-08-15). Data as JSON: /api/errors/ee832d57b87f5fa1. Report an issue: GitHub.