github/copilot-sdk · error · RuntimeError

CLI process not started

Error message

CLI process not started

What it means

RuntimeError raised when creating the stdio JSON-RPC client if self._process is None, i.e. no CLI subprocess exists. The stdio transport wires JSON-RPC over the process's stdin/stdout, which cannot work without a started process.

Solutions

  1. Start the CLI process (client.start() or the appropriate spawn call) before creating the stdio client
  2. Do not reuse a client instance after stop(); create a new CopilotClient
  3. Ensure the start() await completed successfully before calling stdio connect
  4. Check custom code isn't setting self._process = None on cleanup prematurely

Example fix

// before
await client._create_stdio_client()  # no process yet -> RuntimeError

// after
await client.start()          # spawns CLI process
await client._create_stdio_client()
Defensive patterns

Strategy: try-catch

Validate before calling

assert client._process is not None, "start() must complete before stdio connect"

Type guard

def has_process(client) -> bool:
    return getattr(client, "_process", None) is not None

Try / catch

try:
    await client._create_stdio_client()
except RuntimeError as e:
    if "CLI process not started" in str(e):
        await client.start()
        await client._create_stdio_client()
    else:
        raise

Prevention

When it happens

Trigger: Calling _create_stdio_client() (stdio connect path) before the CLI process was spawned, or after it was stopped/cleared (self._process reset to None).

Common situations: Calling connect with stdio mode before start(); reusing a client after stop()/disconnect; a failed prior start left _process None; incorrect ordering of internal API calls in custom tooling.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09). Data as JSON: /api/errors/f0f48470be8dfb7c. Report an issue: GitHub.

Appendix: source

Thrown at python/copilot/client.py:4594

            await self._connect_via_tcp()
        log_timing(
            logger,
            logging.DEBUG,
            "CopilotClient._connect_to_server transport setup complete",
            setup_start,
        )

    async def _connect_via_stdio(self) -> None:
        """
        Connect to the CLI server via stdio pipes.

        Creates a JSON-RPC client using the CLI process's stdin/stdout.

        Raises:
            RuntimeError: If the CLI process is not started.
        """
        if not self._process:
            raise RuntimeError("CLI process not started")

        # Create JSON-RPC client with the process
        self._client = JsonRpcClient(self._process)
        self._client.on_close = self._handle_connection_close
        self._rpc = ServerRpc(self._client)

        # Set up notification handler for session events
        # Note: This handler is called from the event loop (thread-safe scheduling)
        def handle_notification(method: str, params: dict):
            if method == "session.event":
                session_id = params["sessionId"]
                event_dict = params["event"]
                # Convert dict to SessionEvent object
                event = session_event_from_dict(event_dict)
                with self._sessions_lock:
                    session = self._sessions.get(session_id)
                if session:
                    session._dispatch_event(event)

View on GitHub (pinned to cd8cf15dc3)