github/copilot-sdk · error

Server port not available

Error message

Server port not available

What it means

connectViaTcp connects to a CLI server over a TCP socket, but this.runtimePort is unset, so there is no port to dial. The library throws synchronously instead of attempting a connection to an undefined endpoint. It means the server/port discovery step never ran or failed before the TCP connect.

Solutions

  1. Start the CLI server first and await the step that assigns runtimePort before calling connect().
  2. Check server startup logs for port allocation or bind failures that left runtimePort unset.
  3. Create a fresh client instance if a previous stop() cleared the port, rather than reconnecting on a stale instance.
  4. Verify firewall/localhost binding so the server can actually acquire a port in your environment.

Example fix

// before
const client = new CopilotClient({ hosting: 'tcp', ... });
await client.connect(); // runtimePort not yet assigned

// after
const client = new CopilotClient({ hosting: 'tcp', ... });
await client.start(); // boots server, assigns port
await client.connect();
Defensive patterns

Strategy: try-catch

Validate before calling

if (!client.isServerReady?.()) {
  throw new Error('TCP server not ready: start the runtime before connecting');
}

Try / catch

try {
  await client.start();
  await client.connect();
} catch (err) {
  if (err instanceof Error && err.message === 'Server port not available') {
    // inspect server startup logs; recreate client and retry start()
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling connect() on a TCP-hosted CopilotClient before the runtime server (or its port) has been assigned — server startup failed, port discovery was skipped, or the port was cleared during teardown/restart.

Common situations: Server process failed to boot (port allocation failure, crashed binary) before connect(); calling connect() immediately after construction without awaiting the server-start step; reusing a stopped client whose runtimePort was reset.

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

Appendix: source

Thrown at nodejs/src/client.ts:2960

        }

        // Create JSON-RPC connection over stdin/stdout
        this.messageWriter = new TeardownResilientStreamMessageWriter(process.stdout);
        this.connection = createMessageConnection(
            new StreamMessageReader(process.stdin),
            this.messageWriter
        );

        this.attachConnectionHandlers();
        this.connection.listen();
    }

    /**
     * Connect to the CLI server via TCP socket
     */
    private async connectViaTcp(): Promise<void> {
        if (!this.runtimePort) {
            throw new Error("Server port not available");
        }

        return new Promise((resolve, reject) => {
            this.socket = new Socket();

            const connectionTimeout = setTimeout(() => {
                this.socket?.destroy();
                reject(new Error("Timeout connecting to CLI server"));
            }, 10000);

            this.socket.connect(this.runtimePort!, this.actualHost, () => {
                clearTimeout(connectionTimeout);
                // Create JSON-RPC connection
                this.messageWriter = new TeardownResilientStreamMessageWriter(this.socket!);
                this.connection = createMessageConnection(
                    new StreamMessageReader(this.socket!),
                    this.messageWriter
                );

View on GitHub (pinned to cd8cf15dc3)