github/copilot-sdk · error · RuntimeError
Failed to connect to CLI server at
Error message
Failed to connect to CLI server at {host}:{port}: {e} What it means
Wraps socket errors raised by socket.create_connection in CopilotClient._connect_via_tcp. It means the TCP handshake to the CLI server at the given host:port failed - connection refused, wrong port, unreachable host, or the TCP_CONNECTION_TIMEOUT elapsed before the CLI started listening - with the original exception chained as the cause.
Solutions
- Retry the connect with a short delay (server may need a moment after announcement)
- Verify the host configuration matches the interface the CLI bound to (127.0.0.1 vs localhost vs 0.0.0.0)
- Check firewall/VPN rules for the chosen port range
- Confirm the CLI process is still alive when this error occurs
- Configure a fixed known port to avoid announcement/connect races
Example fix
// before
await client._connect_via_tcp() # transient refusal right after startup
// after
for attempt in range(5):
try:
await client._connect_via_tcp()
break
except RuntimeError as e:
if attempt == 4: raise
await asyncio.sleep(0.5) Defensive patterns
Strategy: retry
Validate before calling
import socket
sock = socket.socket()
if not connectable(client._actual_host, client._runtime_port):
schedule_retry() Try / catch
try:
await client._connect_via_tcp()
except RuntimeError as e:
if "Failed to connect to CLI server" in str(e):
await asyncio.sleep(0.5)
await client._connect_via_tcp() # bounded retry loop recommended
else:
raise Prevention
- Add a small bounded retry with backoff after CLI startup
- Match host config to the interface the CLI binds (127.0.0.1 vs ::1)
- Whitelist the port range in firewall/VPN policies
- Use a fixed configured port to avoid announcement/connect races
When it happens
Trigger: socket.create_connection raises OSError during _connect_via_tcp: server not listening on the announced port, wrong host, firewall blocking, IPv6/IPv4 resolution issues, or the CLI died right after announcing its port.
Common situations: Port announced but server crashed immediately (race); connecting to 'localhost' when the server bound only to 127.0.0.1 or ::1; firewall/VPN blocking the port; containers where host differs; port already reused by another process.
Understand the failure class
Background: ECONNREFUSED and "connection refused" / "could not connect to server" errors: what they mean and how to fix them — this error's family across 44 libraries.
Related errors
- failed to connect to CLI server at
- Server port not available
- Cannot connect because TCP host or port are not available
- failed to close socket
- server port not available
AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09).
Data as JSON: /api/errors/0684e752ba706438.
Report an issue: GitHub.
Appendix: source
Thrown at python/copilot/client.py:4674
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
log_timing(
logger,
logging.DEBUG,
"CopilotClient._connect_via_tcp TCP connect complete",
tcp_connect_start,
host=self._actual_host,
port=self._runtime_port,
)
except OSError as e:
raise RuntimeError(
f"Failed to connect to CLI server at {self._actual_host}:{self._runtime_port}: {e}"
)
# Create a file-like wrapper for the socket
sock_file = sock.makefile("rwb", buffering=0)
# Create a mock process object that JsonRpcClient expects
class SocketWrapper:
def __init__(self, sock_file, sock_obj):
self.stdin = sock_file
self.stdout = sock_file
self.stderr = None
self._socket = sock_obj
def terminate(self):
import socket as _socket_mod
# shutdown() sends TCP FIN to the server (triggeringView on GitHub (pinned to cd8cf15dc3)