{"record":{"id":"e03fc4f9217176e6","repo":"containerd/containerd","slug":"errdefs-errnotimplemented-e03fc4","errorCode":"errdefs.ErrNotImplemented","errorMessage":"unsupported events client %T: %w","messagePattern":"unsupported events client %T: %w","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/events/proxy/remote_events.go","lineNumber":61,"sourceCode":"\tswitch c := client.(type) {\n\tcase api.EventsClient:\n\t\treturn &grpcEventsProxy{\n\t\t\tclient: c,\n\t\t}\n\tcase api.TTRPCEventsClient:\n\t\treturn &ttrpcEventsProxy{\n\t\t\tclient: c,\n\t\t}\n\tcase grpc.ClientConnInterface:\n\t\treturn &grpcEventsProxy{\n\t\t\tclient: api.NewEventsClient(c),\n\t\t}\n\tcase *ttrpc.Client:\n\t\treturn &ttrpcEventsProxy{\n\t\t\tclient: api.NewTTRPCEventsClient(c),\n\t\t}\n\tdefault:\n\t\tpanic(fmt.Errorf(\"unsupported events client %T: %w\", client, errdefs.ErrNotImplemented))\n\t}\n}\n\ntype grpcEventsProxy struct {\n\tclient api.EventsClient\n}\n\nfunc (p *grpcEventsProxy) Publish(ctx context.Context, topic string, event events.Event) error {\n\tevt, err := typeurl.MarshalAny(event)\n\tif err != nil {\n\t\treturn err\n\t}\n\treq := &api.PublishRequest{\n\t\tTopic: topic,\n\t\tEvent: typeurl.MarshalProto(evt),\n\t}\n\tif _, err := p.client.Publish(ctx, req); err != nil {\n\t\treturn errgrpc.ToNative(err)","sourceCodeStart":43,"sourceCodeEnd":79,"githubUrl":"https://github.com/containerd/containerd/blob/4246446a2bf7d03837b0244118d858799393bd80/core/events/proxy/remote_events.go#L43-L79","documentation":"NewRemoteEvents accepts a GRPC or TTRPC client; any other client type hits the default case and panics with an ErrNotImplemented error. This is a programming/typing mistake: the library only supports *grpc.ClientConn and *ttrpc.Client for remote event proxying.","triggerScenarios":"Calling events.NewRemoteEvents(ctx, client, ...) with a client other than *grpc.ClientConn or *ttrpc.Client — e.g. passing a wrapped client, an interface value, or nil of the wrong concrete type.","commonSituations":"Passing a custom dialer's connection wrapper; mixing containerd client internals between ttrpc and grpc; a refactor that changed the client type without updating the call.","solutions":["Pass a *grpc.ClientConn or *ttrpc.Client as the client argument","Type-switch or assert the concrete client type before calling NewRemoteEvents","Obtain the correct client from the containerd client instance (e.g. client.Conn() for grpc)"],"exampleFix":"// before\nerr := remote.NewRemoteEvents(ctx, myWrappedClient, ns) // panics\n// after\nconn, _ := myWrappedClient.GRPCConn()\nerr := remote.NewRemoteEvents(ctx, conn, ns)","handlingStrategy":"type-guard","validationCode":"switch c := client.(type) {\ncase *grpc.ClientConn, *ttrpc.Client:\n    // ok\ndefault:\n    return fmt.Errorf(\"unsupported events client %T\", client)\n}","typeGuard":"func isSupportedEventsClient(client any) bool {\n    switch client.(type) {\n    case *grpc.ClientConn, *ttrpc.Client:\n        return true\n    }\n    return false\n}","tryCatchPattern":"func() (err error) {\n    defer func() { if r := recover(); r != nil { err = fmt.Errorf(\"NewRemoteEvents: %v\", r) } }()\n    return remote.NewRemoteEvents(ctx, client, ns)\n}","preventionTips":["Only pass raw *grpc.ClientConn or *ttrpc.Client to NewRemoteEvents","Assert concrete types before calling; NewRemoteEvents panics rather than returning an error","Recover from panics when calling APIs documented to panic"],"tags":["events","panic","not-implemented"],"backgroundTag":"unsupported-client-type","analyzedSha":"4246446a2bf7d03837b0244118d858799393bd80","analyzedAt":"2026-09-02T00:14:43.053Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T06:17:21.866Z"}