github/copilot-sdk · critical · RuntimeError

CLI process exited before announcing port

Error message

CLI process exited before announcing port

What it means

RuntimeError raised when the CLI process's stdout returns EOF while waiting for the 'listening on port N' announcement, meaning the process exited before it could report its TCP port. This indicates the CLI died during startup.

Solutions

  1. Check the CLI binary runs standalone (e.g. copilot --version) and reinstall/upgrade if it crashes
  2. Inspect stderr/logs for the CLI's actual crash reason (invalid flag, missing dep)
  3. Verify the installed CLI version matches what this SDK expects
  4. Increase debugging: enable SDK debug logging to capture CLI output lines before exit
Defensive patterns

Strategy: retry

Validate before calling

import shutil
if shutil.which("copilot") is None:
    raise SystemExit("CLI binary not found or not runnable")

Try / catch

try:
    await client.start()
except RuntimeError as e:
    if "exited before announcing port" in str(e):
        log_cli_stderr_and_reinstall_or_report(e)
    else:
        raise

Prevention

When it happens

Trigger: In TCP mode, read_port() calls process.stdout.readline() which returns b'' (EOF) because the CLI process exited before printing 'listening on port <n>'.

Common situations: Invalid CLI flags or corrupt installation cause the CLI to crash immediately; the binary is a wrong/incompatible version; missing runtime dependencies make the CLI exit at launch; port/permission issues kill the server before announcement.

Related errors


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

Appendix: source

Thrown at python/copilot/client.py:4476

            "CopilotClient._start_cli_server subprocess spawned",
            spawn_start,
        )

        # For stdio mode, we're ready immediately
        if use_stdio:
            return

        # For TCP mode, wait for port announcement
        loop = asyncio.get_event_loop()
        process = self._process  # Capture for closure

        async def read_port():
            if not process or not process.stdout:
                raise RuntimeError("Process not started or stdout not available")
            while True:
                line = await loop.run_in_executor(None, process.stdout.readline)
                if not line:
                    raise RuntimeError("CLI process exited before announcing port")

                line_str = line.decode() if isinstance(line, bytes) else line
                logger.debug("[CLI] %s", line_str.rstrip())
                match = re.search(r"listening on port (\d+)", line_str, re.IGNORECASE)
                if match:
                    self._runtime_port = int(match.group(1))
                    return

        try:
            port_wait_start = time.perf_counter()
            await asyncio.wait_for(read_port(), timeout=10.0)
            log_timing(
                logger,
                logging.DEBUG,
                "CopilotClient._start_cli_server TCP port wait complete",
                port_wait_start,
                port=self._runtime_port,
            )

View on GitHub (pinned to cd8cf15dc3)