temporalio/temporal · error

invalid value for publicClient.forceTLSConfig: %q

Error message

invalid value for publicClient.forceTLSConfig: %q

What it means

Config.Validate checks that publicClient.forceTLSConfig is one of the recognized enum values. If the string is anything other than the supported constants, validation fails with this error naming the offending value via %q. This guards against typo'd TLS enforcement modes silently disabling or misconfiguring TLS.

Source

Thrown at common/config/config.go:712

// Validate validates this config
func (c *Config) Validate() error {
	if err := c.Persistence.Validate(); err != nil {
		return err
	}

	if err := c.Archival.Validate(&c.NamespaceDefaults.Archival); err != nil {
		return err
	}

	_, hasIFE := c.Services[string(primitives.InternalFrontendService)]
	if hasIFE && (c.PublicClient.HostPort != "" || c.PublicClient.ForceTLSConfig != "" || c.PublicClient.HTTPHostPort != "") {
		return fmt.Errorf("when using internal-frontend, publicClient must be empty")
	}

	switch c.PublicClient.ForceTLSConfig {
	case ForceTLSConfigAuto, ForceTLSConfigInternode, ForceTLSConfigFrontend:
	default:
		return fmt.Errorf("invalid value for publicClient.forceTLSConfig: %q", c.PublicClient.ForceTLSConfig)
	}

	return nil
}

// String converts the config object into a string
func (c *Config) String() string {
	var buf bytes.Buffer
	encoder := yaml.NewEncoder(&buf)
	encoder.SetIndent(2)
	_ = encoder.Encode(c)
	maskedYaml, _ := masker.MaskYaml(buf.String(), masker.DefaultYAMLFieldNames)
	return maskedYaml
}

func (r *GroupTLS) IsServerEnabled() bool {
	return r.Server.KeyFile != "" || r.Server.KeyData != ""
}

View on GitHub (pinned to bde624efd1)

Solutions

  1. Set publicClient.forceTLSConfig to one of the exact supported values: auto, internode, or frontend (match the ForceTLSConfig* constant strings)
  2. If unsure, remove the forceTLSConfig key entirely so it stays empty (allowed when no internal-frontend service is configured)
  3. Check the constant definitions in common/config to confirm exact accepted strings

Example fix

// before
publicClient:
  forceTLSConfig: "always"
// after
publicClient:
  forceTLSConfig: "internode"
Defensive patterns

Strategy: validation

Validate before calling

switch strings.TrimSpace(cfg.PublicClient.ForceTLSConfig) {
case config.ForceTLSConfigAuto, config.ForceTLSConfigInternode, config.ForceTLSConfigFrontend, "":
	// ok
default:
	return fmt.Errorf("forceTLSConfig must be auto|internode|frontend, got %q", cfg.PublicClient.ForceTLSConfig)
}

Prevention

When it happens

Trigger: Calling (Config).Validate when c.PublicClient.ForceTLSConfig is set to a string other than ForceTLSConfigAuto, ForceTLSConfigInternode, or ForceTLSConfigFrontend (e.g. "auto " with whitespace, "true", "tls").

Common situations: Typos in the YAML value (e.g. forceTLSConfig: Auto vs auto, or misspellings), copying config from an older temporal version where different values were accepted, or forgetting the field must be blank (empty) when not forcing TLS in deployments without internal-frontend.

Related errors


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