containerd/containerd · error
unsupported client type %T
Error message
unsupported client type %T
What it means
Returned by sandbox.NewClient (core/sandbox/bridge.go:37) when the passed client is neither a *ttrpc.Client nor a grpc.ClientConnInterface. It is a programming/configuration error: only TTRPC and gRPC sandbox clients are supported for bridging to the sandbox service API.
Source
Thrown at core/sandbox/bridge.go:37
// NewClient returns a new sandbox client that handles both GRPC and TTRPC clients.
func NewClient(client any) (api.TTRPCSandboxService, error) {
switch c := client.(type) {
case *ttrpc.Client:
return api.NewTTRPCSandboxClient(c), nil
case grpc.ClientConnInterface:
return &grpcBridge{api.NewSandboxClient(c)}, nil
default:
return nil, fmt.Errorf("unsupported client type %T", client)
}
}
type grpcBridge struct {
client api.SandboxClient
}
var _ api.TTRPCSandboxService = (*grpcBridge)(nil)
func (g *grpcBridge) CreateSandbox(ctx context.Context, request *api.CreateSandboxRequest) (*api.CreateSandboxResponse, error) {
return g.client.CreateSandbox(ctx, request)
}
func (g *grpcBridge) StartSandbox(ctx context.Context, request *api.StartSandboxRequest) (*api.StartSandboxResponse, error) {
return g.client.StartSandbox(ctx, request)
}View on GitHub (pinned to 4246446a2b)
Solutions
- Pass a *ttrpc.Client or a *grpc.ClientConn (any grpc.ClientConnInterface) obtained from the shim's connection.
- Convert your connection: use ttrpc.NewClient(conn) or grpc.NewClient(addr/sock) before calling NewClient.
- Check the caller (Create/Start/getSandbox) is forwarding the correct client type from the container's shim connection.
Example fix
// before cl, err := sandbox.NewClient(ctx, rawNetConn) // after cl, err := sandbox.NewClient(ctx, ttrpc.NewClient(rawNetConn))
Defensive patterns
Strategy: type-guard
Validate before calling
switch c := client.(type) {
case *ttrpc.Client, grpc.ClientConnInterface:
// ok
default:
return fmt.Errorf("need ttrpc.Client or grpc ClientConnInterface, got %T", client)
} Type guard
func isSandboxClient(c any) bool {
switch c.(type) {
case *ttrpc.Client:
return true
case grpc.ClientConnInterface:
return true
}
return false
} Try / catch
if err != nil {
if strings.Contains(err.Error(), "unsupported client type") {
return fmt.Errorf("bridge the connection via ttrpc.NewClient or grpc.NewClient first")
}
return err
} Prevention
- Always obtain the shim client via containerd's connection helpers (ttrpc/gRPC) before calling sandbox APIs.
- Pass *grpc.ClientConn, not net.Conn or custom wrappers.
- Add a compile-time assertion that your client satisfies grpc.ClientConnInterface.
When it happens
Trigger: Calling sandbox.NewClient (directly or via sandbox Create/Start/getSandbox paths) with a client value that is neither *ttrpc.Client nor a gRPC ClientConnInterface.
Common situations: Passing a raw net.Conn, a custom connection wrapper, or a client type from a different transport library into the sandbox bridge; API changes where callers previously passed a different client type.
Related errors
- unsupported content client %T: %w
- error getting writer status: %w
- failed to send write: %w
- commit failed: %w
- NotImplemented
AI-assisted analysis of containerd/containerd@4246446a2b (2026-09-02).
Data as JSON: /api/errors/75b97e5380c0dfda.
Report an issue: GitHub.