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
- Set publicClient.forceTLSConfig to one of the exact supported values: auto, internode, or frontend (match the ForceTLSConfig* constant strings)
- If unsure, remove the forceTLSConfig key entirely so it stays empty (allowed when no internal-frontend service is configured)
- 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
- Reference the ForceTLSConfig* constants in code instead of hardcoding strings
- Never set forceTLSConfig unless you intend to force TLS; empty is valid
- Lint YAML configs against a schema listing the allowed enum values
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
- only one of certData or certFile properties should be specif
- only one of keyData or keyFile properties should be specifie
- cert or key is missing
- only one of caData or caFile properties should be specified
- host name cannot be empty string
AI-assisted analysis of temporalio/temporal@bde624efd1 (2026-09-01).
Data as JSON: /api/errors/1ce20c8010e6b0a8.
Report an issue: GitHub.