hashicorp/nomad · error

no default Consul services client

Error message

no default Consul services client

What it means

ServiceClientWrapper.RegisterAgent in command/agent/consul/service_client.go looks up the service client for structs.ConsulDefaultCluster in an internal map. If no client has been registered for the default Consul cluster, it fails immediately with this error. It is a wrapper-layer invariant error: the multi-cluster Consul client map was never populated for the default cluster before agent registration was attempted.

Source

Thrown at command/agent/consul/service_client.go:511

	scw.lock.Lock()
	defer scw.lock.Unlock()

	for _, serviceClient := range scw.serviceClients {
		// TODO(tgross): we never return error from ServiceClient.Shutdown, so
		// there's no point in returning it here either
		_ = serviceClient.Shutdown()
	}

	return nil
}

func (scw *ServiceClientWrapper) RegisterAgent(role string, services []*structs.Service) error {
	scw.lock.RLock()
	defer scw.lock.RUnlock()

	serviceClient, ok := scw.serviceClients[structs.ConsulDefaultCluster]
	if !ok {
		return errors.New("no default Consul services client")
	}
	return serviceClient.RegisterAgent(role, services)
}

func (scw *ServiceClientWrapper) RegisterWorkload(workload *serviceregistration.WorkloadServices) error {
	scw.lock.RLock()
	defer scw.lock.RUnlock()

	clusters := scw.clustersInWorkload(workload)
	if len(clusters) == 1 {
		return scw.serviceClients[clusters[0]].RegisterWorkload(workload)
	}

	workloadsByCluster := scw.sliceWorkloadsByCluster(workload, clusters)
	for cluster, workload := range workloadsByCluster {
		err := scw.serviceClients[cluster].RegisterWorkload(workload)
		if err != nil {
			return err

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Ensure the Consul client for structs.ConsulDefaultCluster is initialized and added to the ServiceClientWrapper before RegisterAgent is called (check startup order in setupServer/setupClient).
  2. Check the Nomad agent logs for earlier Consul client initialization failures (bad consul.address/TLS settings) that prevented the default client from being created.
  3. Verify the agent's `consul` configuration block is valid and Consul connectivity exists at startup.
  4. If embedding Nomad's service_client package, call the constructor that registers the default cluster client rather than building the map manually.

Example fix

// before: wrapper created with no default client
scw := &ServiceClientWrapper{serviceClients: map[string]ServiceClient{}}
scw.RegisterAgent(role, services) // panics into error
// after: register the default cluster client first
scw.serviceClients[structs.ConsulDefaultCluster] = serviceClient
Defensive patterns

Strategy: try-catch

Validate before calling

// before agent self-registration, check the wrapper has the default client
if _, ok := wrapper.HasClient(structs.ConsulDefaultCluster); !ok {
    return errors.New("consul default client not initialized; check consul config")
}

Try / catch

if err := scw.RegisterAgent(role, services); err != nil {
    if strings.Contains(err.Error(), "no default Consul services client") {
        log.Error("Consul client not initialized at startup; verify consul block and init order")
        return err
    }
    return err
}

Prevention

When it happens

Trigger: Calling RegisterAgent(role, services) (via setupServer/setupClient) when scw.serviceClients lacks the structs.ConsulDefaultCluster entry — i.e. the Consul service client was not initialized/added before the Nomad agent registered its own services.

Common situations: Nomad agent config with Consul integration partially disabled or the consul client failing to initialize at startup; race at boot where agent self-registration runs before the default cluster client is added; custom code constructing a ServiceClientWrapper without calling the init/add for the default cluster.

Related errors


AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04). Data as JSON: /api/errors/05653a0f4d83d684. Report an issue: GitHub.