github/copilot-sdk · error · RuntimeError

Server port not available

Error message

Server port not available

What it means

RuntimeError raised by CopilotClient._connect_via_tcp when the runtime port is missing or unknown, so there is no host:port endpoint to dial. Per the method's docstring it fires when the server port is not available or the connection fails; typically the spawned CLI never reported its listening port during startup.

Solutions

  1. Use the normal start/connect flow so the port announcement is awaited before TCP connect
  2. If connecting to an external server, configure host/port explicitly instead of relying on the announced port
  3. Verify the client is not in stdio/FFI mode when calling the TCP connect path
  4. Recover from failed startups by creating a fresh client instance

Example fix

// before
await client._connect_via_tcp()  # _runtime_port never set -> RuntimeError

// after
await client.start()  # waits for 'listening on port N', sets _runtime_port
await client._connect_via_tcp()
Defensive patterns

Strategy: validation

Validate before calling

if not getattr(client, "_runtime_port", None):
    await client.start()  # ensure port announcement completed first

Type guard

def has_port(client) -> bool:
    return bool(getattr(client, "_runtime_port", 0))

Try / catch

try:
    await client._connect_via_tcp()
except RuntimeError as e:
    if "Server port not available" in str(e):
        await client.start()
        await client._connect_via_tcp()
    else:
        raise

Prevention

When it happens

Trigger: Calling _connect_via_tcp() before the port-announcement wait completed, after TCP startup failed to set _runtime_port, or when configured for a mode (stdio/FFI) that never sets a runtime port.

Common situations: Mixing transports: spawning the CLI in stdio mode then connecting via TCP; skipping the port wait step; a previous startup error left _runtime_port unset; manually constructing the client and calling connect internals out of order.

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/fd1bb591e0f10657. Report an issue: GitHub.

Appendix: source

Thrown at python/copilot/client.py:4646

        )
        register_client_session_api_handlers(self._client, self._get_client_session_handlers)
        self._register_client_global_handlers()

        # Start listening for messages
        loop = asyncio.get_running_loop()
        self._client.start(loop)

    async def _connect_via_tcp(self) -> None:
        """
        Connect to the CLI server via TCP socket.

        Creates a TCP connection to the server at the configured host and port.

        Raises:
            RuntimeError: If the server port is not available or connection fails.
        """
        if not self._runtime_port:
            raise RuntimeError("Server port not available")

        # Create a TCP socket connection with timeout. create_connection resolves
        # both IPv4 and IPv6 addresses instead of forcing AF_INET.
        import socket

        # Connection timeout constant
        TCP_CONNECTION_TIMEOUT = 10  # seconds

        try:
            tcp_connect_start = time.perf_counter()
            logger.info(
                "CopilotClient._connect_via_tcp connecting to CLI server",
                extra={"host": self._actual_host, "port": self._runtime_port},
            )
            sock = socket.create_connection(
                (self._actual_host, self._runtime_port), timeout=TCP_CONNECTION_TIMEOUT
            )
            sock.settimeout(None)  # Remove timeout after connection

View on GitHub (pinned to cd8cf15dc3)