temporalio/temporal · error
when using internal-frontend, publicClient must be empty
Error message
when using internal-frontend, publicClient must be empty
What it means
This error comes from Config validation in temporal's config package. When the service set defines the internal-frontend service, the publicClient block must be fully omitted, because traffic intended for the public frontend is instead routed through the internal frontend; keeping a publicClient config is contradictory. Validation runs as part of config load/validate and aborts startup with this message.
Source
Thrown at common/config/config.go:706
const (
ForceTLSConfigAuto = ""
ForceTLSConfigInternode = "internode"
ForceTLSConfigFrontend = "frontend"
)
// 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)View on GitHub (pinned to bde624efd1)
Solutions
- Remove the entire publicClient block (hostPort, forceTLSConfig, httpHostPort) from the YAML config when internalFrontend is enabled
- Remove the corresponding fields from the programmatically constructed common.Config struct
- Re-run config load to confirm validation passes
Example fix
// before services: internalFrontend: publicClient: hostPort: "temporal.example.com:7233" // after services: internalFrontend: # publicClient removed entirely
Defensive patterns
Strategy: validation
Validate before calling
func hasPublicClientFields(c *config.Config) bool {
return c.PublicClient.HostPort != "" ||
c.PublicClient.ForceTLSConfig != "" ||
c.PublicClient.HTTPHostPort != ""
}
_, hasIFE := c.Services[string(primitives.InternalFrontendService)]
if hasIFE && hasPublicClientFields(c) {
// fix before calling Validate/LoadConfig: delete publicClient block
} Prevention
- When adding the internalFrontend service, always remove the publicClient section in the same change
- Keep environment-specific config overlays free of publicClient unless the public frontend topology is used
- Run config validation in CI to catch invalid service/publicClient combinations before deploy
When it happens
Trigger: Calling (Config).Validate (via LoadConfig/load) when c.Services contains key "internalFrontend" (primitives.InternalFrontendService) while c.PublicClient.HostPort != "" OR c.PublicClient.ForceTLSConfig != "" OR c.PublicClient.HTTPPort/HTTPHostPort is set.
Common situations: Operators deploying temporal with the internal-frontend topology (self-hosted clusters fronting via internal frontend) copy a stock config that still has a publicClient section, or add internalFrontend to services without removing the previously used publicClient.HostPort/forceTLSConfig/httpTransport settings.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- env, config, zone can not be set if configFilePath is set
- 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
AI-assisted analysis of temporalio/temporal@bde624efd1 (2026-09-01).
Data as JSON: /api/errors/bd2b7250551d2fa6.
Report an issue: GitHub.