github/copilot-sdk · error

unknown RuntimeConnection type: %T

Error message

unknown RuntimeConnection type: %T

What it means

NewClient panics when the Connection option implements RuntimeConnection with a type the SDK does not recognize. The connection switch in NewClient handles StdioConnection, TCPConnection, URIConnection and InProcessConnection; anything else falls to the default branch. This is almost always a custom connection type or a value that does not actually implement the intended interface.

Solutions

  1. Use one of the supported connection types: StdioConnection, TCPConnection, URIConnection, or InProcessConnection.
  2. Remove custom wrappers; configure behavior via ClientOptions instead.
  3. Check the %T value in the panic message against the SDK's exported connection types after upgrading.

Example fix

// before
client := clientpkg.NewClient(&clientpkg.Options{Connection: myLoggingConn{inner: clientpkg.StdioConnection{}}})
// after
client := clientpkg.NewClient(&clientpkg.Options{
    Connection: clientpkg.StdioConnection{},
    // custom behavior via options/hooks instead of a wrapper type
})
Defensive patterns

Strategy: type-guard

Validate before calling

switch c := opts.Connection.(type) {
case clientpkg.StdioConnection, clientpkg.TCPConnection, clientpkg.URIConnection, clientpkg.InProcessConnection:
    // ok
case nil:
    // default transport
default:
    return fmt.Errorf("unsupported connection type %T", c)
}

Type guard

func isSupportedConnection(c clientpkg.RuntimeConnection) bool {
    switch c.(type) {
    case clientpkg.StdioConnection, clientpkg.TCPConnection, clientpkg.URIConnection, clientpkg.InProcessConnection:
        return true
    }
    return false
}

Prevention

When it happens

Trigger: Passing a user-defined struct (or a wrongly-typed value, e.g. *MyConn vs MyConn, or a nil typed pointer) as Options.Connection so it satisfies RuntimeConnection but matches no known case. Panic at go/client.go:286 with the Go type in the message (%T).

Common situations: Wrapping a connection to intercept traffic; upgrading the SDK where an older custom connection type is no longer a recognized case; passing nil interface vs typed nil confusion.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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

Appendix: source

Thrown at go/client.go:286

			client.cliArgs = append([]string{}, conn.Args...)
		}
		client.port = conn.Port
		client.tcpConnectionToken = conn.ConnectionToken
	case URIConnection:
		if conn.URL == "" {
			panic("URIConnection requires a non-empty URL")
		}
		host, port := parseCLIURL(conn.URL)
		client.actualHost = host
		client.actualPort = port
		client.isExternalServer = true
		client.useStdio = false
		client.tcpConnectionToken = conn.ConnectionToken
	case InProcessConnection:
		client.useStdio = false
		client.useInProcess = true
	default:
		panic(fmt.Sprintf("unknown RuntimeConnection type: %T", connection))
	}

	// Validate transport-specific option constraints (fail loud). The in-process
	// transport loads the runtime into this process, whose single environment
	// block, process-global working directory, and shared telemetry state cannot
	// carry per-client values. Child-process transports may set env via either
	// the client-level option or the connection, but not both.
	validateEnvironmentOptions(connection, &opts)

	// Validate auth options when connecting to an external runtime.
	if client.isExternalServer && (opts.GitHubToken != "" || opts.UseLoggedInUser != nil) {
		panic("GitHubToken and UseLoggedInUser cannot be used with URIConnection (external runtime manages its own auth)")
	}

	// For child-process transports, a connection-level env takes precedence over
	// the client-level env (setting both was rejected above). Resolve it before
	// defaulting so an explicit empty connection env stays authoritative.
	if cp, ok := connection.(childProcessConnection); ok {

View on GitHub (pinned to cd8cf15dc3)