jaegertracing/jaeger · error

%s.tls.* options cannot be used when %s is false

Error message

%s.tls.* options cannot be used when %s is false

What it means

tlscfg.ClientFlagsConfig.InitFromViper builds a client TLS options struct from Viper settings. If tls.enabled is false but any other tls.* field was set, the struct differs from the zero value and the call fails, because TLS options are meaningless (and likely a mistake) when TLS is disabled. The reflect.DeepEqual against an empty options struct detects 'extra' TLS settings.

Source

Thrown at internal/config/tlscfg/flags.go:77

	flags.String(c.Prefix+tlsMinVersion, "", "Minimum TLS version supported (Possible values: 1.0, 1.1, 1.2, 1.3)")
	flags.String(c.Prefix+tlsMaxVersion, "", "Maximum TLS version supported (Possible values: 1.0, 1.1, 1.2, 1.3)")
	flags.Duration(c.Prefix+tlsReloadInterval, 0, "The duration after which the certificate will be reloaded (0s means will not be reloaded)")
}

// InitFromViper creates tls.Config populated with values retrieved from Viper.
func (c ClientFlagsConfig) InitFromViper(v *viper.Viper) (configtls.ClientConfig, error) {
	var p options
	p.Enabled = v.GetBool(c.Prefix + tlsEnabled)
	p.CAPath = v.GetString(c.Prefix + tlsCA)
	p.CertPath = v.GetString(c.Prefix + tlsCert)
	p.KeyPath = v.GetString(c.Prefix + tlsKey)
	p.ServerName = v.GetString(c.Prefix + tlsServerName)
	p.SkipHostVerify = v.GetBool(c.Prefix + tlsSkipHostVerify)

	if !p.Enabled {
		var empty options
		if !reflect.DeepEqual(&p, &empty) {
			return configtls.ClientConfig{}, fmt.Errorf("%s.tls.* options cannot be used when %s is false", c.Prefix, c.Prefix+tlsEnabled)
		}
	}

	return p.ToOtelClientConfig(), nil
}

// InitFromViper creates tls.Config populated with values retrieved from Viper.
func (c ServerFlagsConfig) InitFromViper(v *viper.Viper) (configoptional.Optional[configtls.ServerConfig], error) {
	var p options
	p.Enabled = v.GetBool(c.Prefix + tlsEnabled)
	p.CertPath = v.GetString(c.Prefix + tlsCert)
	p.KeyPath = v.GetString(c.Prefix + tlsKey)
	p.ClientCAPath = v.GetString(c.Prefix + tlsClientCA)
	if s := v.GetString(c.Prefix + tlsCipherSuites); s != "" {
		p.CipherSuites = strings.Split(stripWhiteSpace(v.GetString(c.Prefix+tlsCipherSuites)), ",")
	}
	p.MinVersion = v.GetString(c.Prefix + tlsMinVersion)
	p.MaxVersion = v.GetString(c.Prefix + tlsMaxVersion)

View on GitHub (pinned to 806f444784)

Solutions

  1. Set <prefix>.tls.enabled: true if you actually want TLS
  2. Remove all <prefix>.tls.* options other than enabled when TLS is disabled
  3. Check Viper/env for stray keys like <prefix>.tls.skip-host-verify=true left from defaults
  4. Inspect the merged Viper config (v.AllSettings()) to find which tls.* key is non-empty

Example fix

# before
storage.tls.enabled: false
storage.tls.skip-host-verify: true
# after
storage.tls.enabled: false
Defensive patterns

Strategy: validation

Validate before calling

if !tlsEnabled {
    for k := range viper.AllSettings() {
        if strings.HasPrefix(k, prefix+".tls.") && k != prefix+".tls.enabled" {
            return fmt.Errorf("remove %s: tls is disabled", k)
        }
    }
}
err := tlscfg.ClientFlagsConfig{Prefix: prefix}.InitFromViper(v)

Try / catch

if err := cfg.InitFromViper(v); err != nil {
    if strings.Contains(err.Error(), "cannot be used when") {
        // strip or fix tls.* keys, re-init
    }
    return err
}

Prevention

When it happens

Trigger: Calling InitFromViper for a client prefix where <prefix>.tls.enabled is false/absent while one or more <prefix>.tls.* keys (ca, cert, key, server-name, skip-host-verify, etc.) are set in Viper.

Common situations: Disabling TLS by setting enabled: false but forgetting to remove the cert/key lines; a config template that always emits tls.* keys; leftover keys from a previous TLS setup in YAML or environment variables.

Understand the failure class

Related errors


AI-assisted analysis of jaegertracing/jaeger@806f444784 (2026-09-01). Data as JSON: /api/errors/c69fc16fc6c6282d. Report an issue: GitHub.