github/copilot-sdk · error

server port not available

Error message

server port not available

What it means

Returned by connectViaTCP when the Client was configured for TCP transport but the actual server port is still 0, i.e. no port was discovered or provided. The client cannot dial a TCP endpoint without a port, so it fails fast before attempting a connection.

Solutions

  1. Ensure the CLI server is started first and its port is captured/assigned to the client configuration before connecting.
  2. Pass an explicit port in the client options if the server's port is known and static.
  3. Upgrade the CLI to a version that announces its listening port.
  4. Confirm the transport mode matches how the CLI was launched (stdio vs TCP).

Example fix

// before
c := client.New(client.WithTransport("tcp")) // port never set

// after
c := client.New(client.WithTransport("tcp"), client.WithPort(cliServerPort)) // port from launched server
Defensive patterns

Strategy: validation

Validate before calling

if cfg.Transport == "tcp" && cfg.Port == 0 {
    return fmt.Errorf("tcp transport requires an explicit or discovered port")
}

Prevention

When it happens

Trigger: Calling Client connect logic with TCP transport when the CLI server never reported its port (actualPort == 0): the server failed to start listening, the port discovery step was skipped or failed, or no port was passed in configuration.

Common situations: CLI binary too old to report its port; server startup failed before binding a socket; configuration omitted the port while forcing TCP; race where connect is called before the server's port file/announcement is ready.

Understand the failure class

Background: "missing required config value" errors: why libraries refuse to start when a configuration key is empty, unset, or blank — this error's family across 48 libraries.

Related errors


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

Appendix: source

Thrown at go/client.go:2435

		close(done)
	}()
}

// connectToServer establishes a connection to the server.
func (c *Client) connectToServer(ctx context.Context) error {
	if c.useStdio || c.useInProcess {
		// Already connected: stdio in startCLIServer, FFI streams in startInProcess.
		return nil
	}

	// Connect via TCP
	return c.connectViaTCP(ctx)
}

// connectViaTCP connects to the CLI server via TCP socket.
func (c *Client) connectViaTCP(ctx context.Context) error {
	if c.actualPort == 0 {
		return fmt.Errorf("server port not available")
	}

	// Merge a 10-second timeout with the caller's context so whichever
	// deadline comes first wins.
	address := net.JoinHostPort(c.actualHost, fmt.Sprintf("%d", c.actualPort))
	dialCtx, cancel := context.WithTimeout(ctx, 10*time.Second)
	defer cancel()
	var dialer net.Dialer
	conn, err := dialer.DialContext(dialCtx, "tcp", address)
	if err != nil {
		return fmt.Errorf("failed to connect to CLI server at %s: %w", address, err)
	}

	c.conn = conn

	// Create JSON-RPC client with the connection
	c.client = jsonrpc2.NewClient(conn, conn)
	if c.processDone != nil {

View on GitHub (pinned to cd8cf15dc3)