temporalio/temporal · error

missingServiceInStaticHosts

missingServiceInStaticHosts

Error message

%w: %v

What it means

Sentinel error missingServiceInStaticHosts wrapped with the offending service name. When static hosts are provided via WithHosts (hostsByService), every default service (frontend, history, matching, worker, etc.) must have at least one host entry; a missing entry aborts server construction.

Source

Thrown at temporal/fx.go:292

			esHttpClient, err = esclient.NewAwsHttpClient(esConfig.AWSRequestSigning)
			if err != nil {
				return serverOptionsProvider{}, fmt.Errorf("unable to create AWS HTTP client for Elasticsearch: %w", err)
			}
		}

		esClient, err = esclient.NewClient(esConfig, esHttpClient, logger)
		if err != nil {
			return serverOptionsProvider{}, fmt.Errorf("unable to create Elasticsearch client (URL = %v, username = %q): %w",
				esConfig.URL.Redacted(), esConfig.Username, err)
		}
	}

	// check that when static hosts are defined, they are defined for all required hosts
	if len(so.hostsByService) > 0 {
		for _, service := range DefaultServices {
			hosts := so.hostsByService[primitives.ServiceName(service)]
			if len(hosts.All) == 0 {
				return serverOptionsProvider{}, fmt.Errorf("%w: %v", missingServiceInStaticHosts, service)
			}
		}
	}

	if so.config.Global.Authorization.RemoteClusterAuth.Require && so.tokenProvider == nil {
		return serverOptionsProvider{}, errors.New("global.authorization.remoteClusterAuth.require is true but no TokenProvider is configured: use WithTokenProvider")
	}
	// TokenCredentials require TLS (RFC 9700); without a remote-cluster TLS source the first
	// cross-cluster dial would fatal-log, with no clear "you forgot TLS" diagnostic.
	// Coarse check: any remote-cluster TLS entry passes; per-hostname config is still validated
	// lazily on first dial.
	if so.tokenProvider != nil && so.tlsConfigProvider == nil && len(so.config.Global.TLS.RemoteClusters) == 0 {
		return serverOptionsProvider{}, errors.New("WithTokenProvider is set but no remote-cluster TLS is configured: supply global.tls.remoteClusters in config, or pass a provider via WithTLSConfigProvider")
	}

	return serverOptionsProvider{
		ServerOptions:              so,
		StopChan:                   stopChan,

View on GitHub (pinned to bde624efd1)

Solutions

  1. Add the missing service to the WithHosts map with at least one host
  2. Reconcile the host map against temporal.DefaultServices programmatically
  3. If static hosts are no longer needed, remove WithHosts and rely on default membership resolution

Example fix

// before
opts := temporal.WithHosts(map[primitives.ServiceName]temporal.Hosts{
  primitives.FrontendService: {All: []string{"h1:7233"}},
  primitives.HistoryService:  {All: []string{"h1:7234"}},
})
// after
opts := temporal.WithHosts(map[primitives.ServiceName]temporal.Hosts{
  primitives.FrontendService: {All: []string{"h1:7233"}},
  primitives.HistoryService:  {All: []string{"h1:7234"}},
  primitives.MatchingService: {All: []string{"h1:7235"}},
  primitives.WorkerService:   {All: []string{"h1:7239"}},
})
Defensive patterns

Strategy: validation

Validate before calling

for _, svc := range temporal.DefaultServices {
    if len(hostsByService[svc].All) == 0 {
        return fmt.Errorf("missing static hosts for %s", svc)
    }
}

Prevention

When it happens

Trigger: Calling WithHosts with a map that omits one of temporal.DefaultServices; any service name in the map has an empty hosts.All list.

Common situations: Adding a new Temporal service (e.g. internal-frontend) to DefaultServices but not updating the static host map in operator tooling or tests; copy-pasted host config that forgot one service.

Related errors


AI-assisted analysis of temporalio/temporal@bde624efd1 (2026-09-01). Data as JSON: /api/errors/750575d93165ead2. Report an issue: GitHub.