temporalio/temporal · error

invalid service %q in service list %v

Error message

invalid service %q in service list %v

What it means

Returned by serverOptions.loadAndValidate when a service name supplied via WithServices (or the services list) is not one of the known Temporal services: frontend, internal-frontend, history, matching, worker. It is a fast-fail configuration validation so an unknown/typo'd service name aborts before any config load or service startup.

Source

Thrown at temporal/server_options.go:87

	}
)

func newServerOptions(opts []ServerOption) *serverOptions {
	so := &serverOptions{
		// Set defaults here.
		persistenceServiceResolver: resolver.NewNoopResolver(),
	}
	for _, opt := range opts {
		opt.apply(so)
	}

	return so
}

func (so *serverOptions) loadAndValidate() error {
	for serviceName := range so.serviceNames {
		if !slices.Contains(Services, string(serviceName)) {
			return fmt.Errorf("invalid service %q in service list %v", serviceName, so.serviceNames)
		}
	}

	if so.config == nil {
		err := so.loadConfig()
		if err != nil {
			return fmt.Errorf("unable to load config: %w", err)
		}
	}

	err := so.validateConfig()
	if err != nil {
		return fmt.Errorf("config validation error: %w", err)
	}

	return nil
}

View on GitHub (pinned to bde624efd1)

Solutions

  1. Use one of the exact supported names: frontend, internal-frontend, history, matching, worker (see temporal.Services in temporal/server.go)
  2. Fix typos and casing — the check is a plain string comparison against the Services slice
  3. If you intended internal-frontend, confirm your Temporal build/version supports it before including it
  4. If the list comes from a config file, validate its contents against the supported set before constructing the server
  5. If you need a custom service, that is not supported by this option set — remove the entry and rely on the standard services

Example fix

// before
srv, err := temporal.NewServer(
	temporal.WithServices("front-end", "history", "matching", "worker"),
)
// invalid service "front-end" in service list [front-end history matching worker]

// after
srv, err := temporal.NewServer(
	temporal.WithServices(temporal.FrontendService, "history", "matching", "worker"),
)
Defensive patterns

Strategy: validation

Validate before calling

func validServices(names []string) error {
	for _, n := range names {
		switch n {
		case "frontend", "internal-frontend", "history", "matching", "worker":
		default:
			return fmt.Errorf("invalid service %q; supported: frontend, internal-frontend, history, matching, worker", n)
		}
	}
	return nil
}
// call validServices(myServices) before temporal.NewServer(temporal.WithServices(myServices...))

Try / catch

srv, err := temporal.NewServer(temporal.WithServices(names...))
if err != nil && strings.Contains(err.Error(), "invalid service") {
	log.Fatalf("fix service list: %v", err)
}

Prevention

When it happens

Trigger: Passing temporal.WithServices("frontend1"), a typo like "front-end" or "workers", or a service name valid in an older/newer Temporal version (e.g. "internal-frontend" on a build that doesn't define it) to temporal.NewServer, or listing an invalid service in the services config.

Common situations: Typos or wrong casing in WithServices arguments; copying service names from another product/version; enabling internal-frontend when the build/config doesn't support it; programmatic service selection built from a config file that contains an unexpected value.

Related errors


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