{"record":{"id":"321db6ec7ac45b98","repo":"grpc/grpc-go","slug":"xdsclient-clientconfig-is-nil","errorCode":null,"errorMessage":"xdsclient: clientConfig is nil","messagePattern":"xdsclient: clientConfig is nil","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/xds/clients/xdsclient/channel.go","lineNumber":86,"sourceCode":"\tserverConfig       *ServerConfig           // Configuration of the server to connect to.\n\tclientConfig       *Config                 // Complete xDS client configuration, used to decode resources.\n\teventHandler       xdsChannelEventHandler  // Callbacks for ADS stream events.\n\tbackoff            func(int) time.Duration // Backoff function to use for stream retries. Defaults to exponential backoff, if unset.\n\twatchExpiryTimeout time.Duration           // Timeout for ADS resource watch expiry.\n\tlogPrefix          string                  // Prefix to use for logging.\n}\n\n// newXDSChannel creates a new xdsChannel instance with the provided options.\n// It performs basic validation on the provided options and initializes the\n// xdsChannel with the necessary components.\nfunc newXDSChannel(opts xdsChannelOpts) (*xdsChannel, error) {\n\tswitch {\n\tcase opts.transport == nil:\n\t\treturn nil, errors.New(\"xdsclient: transport is nil\")\n\tcase opts.serverConfig == nil:\n\t\treturn nil, errors.New(\"xdsclient: serverConfig is nil\")\n\tcase opts.clientConfig == nil:\n\t\treturn nil, errors.New(\"xdsclient: clientConfig is nil\")\n\tcase opts.eventHandler == nil:\n\t\treturn nil, errors.New(\"xdsclient: eventHandler is nil\")\n\t}\n\n\txc := &xdsChannel{\n\t\ttransport:    opts.transport,\n\t\tserverConfig: opts.serverConfig,\n\t\tclientConfig: opts.clientConfig,\n\t\teventHandler: opts.eventHandler,\n\t\tclosed:       syncutil.NewEvent(),\n\t}\n\n\tl := grpclog.Component(\"xds\")\n\tlogPrefix := opts.logPrefix + fmt.Sprintf(\"[xds-channel %p] \", xc)\n\txc.logger = igrpclog.NewPrefixLogger(l, logPrefix)\n\n\tif opts.backoff == nil {\n\t\topts.backoff = backoff.DefaultExponential.Backoff","sourceCodeStart":68,"sourceCodeEnd":104,"githubUrl":"https://github.com/grpc/grpc-go/blob/0c51461d27177d997e14c642fe18c11668fc09a3/internal/xds/clients/xdsclient/channel.go#L68-L104","documentation":"`newXDSChannel` (channel.go:79) also requires `clientConfig` (*Config) — the full xDS client configuration used to decode resources. The channel uses it (including its Node proto) when building ADS requests and when interpreting resource responses. A nil clientConfig fails at channel.go:85-86.","triggerScenarios":"Triggered when `newXDSChannel` is invoked with `opts.clientConfig == nil`. As with the other channel.go guards, this is an internal-API misuse: the XDSClient is expected to forward its own *Config.","commonSituations":"A refactor that drops the clientConfig field when assembling xdsChannelOpts; a custom XDSClient implementation that does not hold a Config; tests that build opts manually without copying the client's Config.","solutions":["Always pass the XDSClient's stored *Config (c.config) into xdsChannelOpts.clientConfig.","If you write your own channel factory, validate clientConfig is non-nil at the entry point.","Cover channel construction with a unit test that asserts the error path for a nil clientConfig."],"exampleFix":"// before\nopts := xdsChannelOpts{transport: t, serverConfig: sc, eventHandler: h}\nxc, err := newXDSChannel(opts) // err: clientConfig is nil\n\n// after\nopts := xdsChannelOpts{transport: t, serverConfig: sc, clientConfig: c.config, eventHandler: h}\nxc, err := newXDSChannel(opts)","handlingStrategy":"validation","validationCode":"// Ensure the client's own config is wired through.\nfunc (c *XDSClient) safeNewChannel(opts xdsChannelOpts) (*xdsChannel, error) {\n    if c.config == nil {\n        return nil, errors.New(\"cannot build xDS channel: client config is nil\")\n    }\n    opts.clientConfig = c.config\n    return newXDSChannel(opts)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always forward the XDSClient's stored *Config when assembling xdsChannelOpts.","Add a linter or code-review check that any code constructing xdsChannelOpts sets all four mandatory fields.","Write a unit test that asserts each of the four nil-field error paths."],"tags":["grpc","xds","xdschannel","config-validation","programming-error"],"backgroundTag":null,"analyzedSha":"0c51461d27177d997e14c642fe18c11668fc09a3","analyzedAt":"2026-08-11T14:49:15.055Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}