grpc/grpc-go · error
no ResourceType implementation found for typeURL
Error message
no ResourceType implementation found for typeURL %q
What it means
Reported via the watcher when WatchResource is called with a typeURL that has no entry in Config.ResourceTypes (clientimpl_watchers.go:69). Note: the message formats rType.TypeURL, but rType is the zero-value ResourceType returned from a failed map lookup, so the printed typeURL is empty - this is a known quirk; the actual requested typeURL is the function argument.
Solutions
- Populate Config.ResourceTypes with a ResourceType (TypeName, TypeURL, Decoder) for every typeURL you intend to watch before constructing the XDSClient.
- Confirm the requested typeURL string matches the key in the map exactly (including the 'type.googleapis.com/' prefix).
- Register the built-in resource types (LDS/RDS/CDS/EDS) via the package's helper if you need standard xDS.
Example fix
// before
cfg := &xdsclient.Config{} // ResourceTypes empty
c, _ := xdsclient.New(cfg)
c.WatchResource("type.googleapis.com/envoy.config.listener.v3.Listener", n, w)
// after
cfg := &xdsclient.Config{
ResourceTypes: map[string]xdsclient.ResourceType{
listenerTypeURL: {TypeURL: listenerTypeURL, TypeName: "Listener", Decoder: listenerDecoder},
},
}
c, _ := xdsclient.New(cfg)
c.WatchResource(listenerTypeURL, n, w) Defensive patterns
Strategy: validation
Validate before calling
func validateTypeURL(cfg *xdsclient.Config, typeURL string) error {
if _, ok := cfg.ResourceTypes[typeURL]; !ok {
return fmt.Errorf("typeURL %q not in Config.ResourceTypes", typeURL)
}
return nil
}
// call before xdsClient.WatchResource Try / catch
cancel := xdsClient.WatchResource(typeURL, name, watcher)
// The watcher's ResourceError will receive the message; handle it there:
// if strings.Contains(err.Error(), "no ResourceType implementation") { fix config } Prevention
- Register every ResourceType in Config.ResourceTypes before constructing the XDSClient.
- Define typeURL constants and reuse them at watch sites.
- Unit-test that each typeURL you watch resolves to a registered ResourceType.
When it happens
Trigger: xdsClient.WatchResource("type.googleapis.com/foo.Bar", name, watcher) is called, but the Config.ResourceTypes map used to construct the XDSClient has no key "type.googleapis.com/foo.Bar". The client schedules a ResourceError on the watcher and returns a no-op cancel.
Common situations: Caller requests a resource type (e.g. a custom or newer typeURL) that the client was not configured to handle at construction; typo in the typeURL; the XDSClient was built with an empty or partial ResourceTypes map.
Related errors
- authority not found in the config for resource
- extauthz: empty grpc_service provided in config
- extauthz: missing default_value in deny_at_disable
- extauthz: missing default_value in filter_enabled
- grpctransport: config
AI-assisted analysis of grpc/grpc-go@0c51461d27 (2026-08-11).
Data as JSON: /api/errors/678c429ce0ddeec5.
Report an issue: GitHub.
Appendix: source
Thrown at internal/xds/clients/xdsclient/clientimpl_watchers.go:69
// The returned function cancels the watch and prevents future calls to the
// watcher.
func (c *XDSClient) WatchResource(typeURL, resourceName string, watcher ResourceWatcher) (cancel func()) {
// Return early if the client is already closed.
if c.done.HasFired() {
logger.Warningf("Watch registered for type %q, but client is closed", typeURL)
return func() {}
}
watcher = &wrappingWatcher{
ResourceWatcher: watcher,
nodeID: c.config.Node.ID,
}
rType, ok := c.config.ResourceTypes[typeURL]
if !ok {
logger.Warningf("ResourceType implementation for resource type url %q is not found", rType.TypeURL)
c.serializer.TrySchedule(func(context.Context) {
watcher.ResourceError(fmt.Errorf("no ResourceType implementation found for typeURL %q", rType.TypeURL), func() {})
})
return func() {}
}
n := xdsresource.ParseName(resourceName)
a := c.getAuthorityForResource(n)
if a == nil {
logger.Warningf("Watch registered for name %q of type %q, authority %q is not found", rType.TypeName, resourceName, n.Authority)
c.serializer.TrySchedule(func(context.Context) {
watcher.ResourceError(fmt.Errorf("authority %q not found in the config for resource %q", n.Authority, resourceName), func() {})
})
return func() {}
}
// The watchResource method on the authority is invoked with n.String()
// instead of resourceName because n.String() canonicalizes the given name.
// So, two resource names which don't differ in the query string, but only
// differ in the order of context params will result in the same resource
// being watched by the authority.View on GitHub (pinned to 0c51461d27)