fatedier/frp · warning

%s is invalid when transport.tls.enable is false

Error message

%s is invalid when transport.tls.enable is false

What it means

A warning (not fatal) emitted when transport.tls.enable is false (or unset) but TLS material fields are still set: certFile, keyFile, or trustedCaFile. The field name is interpolated into %s. frp tells you these values will be ignored because TLS is off.

Source

Thrown at pkg/config/v1/validation/client.go:158

	return errs
}

func validateTransportConfig(c *v1.ClientTransportConfig) (Warning, error) {
	var (
		warnings Warning
		errs     error
	)

	if c.HeartbeatTimeout > 0 && c.HeartbeatInterval > 0 {
		if c.HeartbeatTimeout < c.HeartbeatInterval {
			errs = AppendError(errs, fmt.Errorf("invalid transport.heartbeatTimeout, heartbeat timeout should not less than heartbeat interval"))
		}
	}

	if !lo.FromPtr(c.TLS.Enable) {
		checkTLSConfig := func(name string, value string) Warning {
			if value != "" {
				return fmt.Errorf("%s is invalid when transport.tls.enable is false", name)
			}
			return nil
		}

		warnings = AppendError(warnings, checkTLSConfig("transport.tls.certFile", c.TLS.CertFile))
		warnings = AppendError(warnings, checkTLSConfig("transport.tls.keyFile", c.TLS.KeyFile))
		warnings = AppendError(warnings, checkTLSConfig("transport.tls.trustedCaFile", c.TLS.TrustedCaFile))
	}

	if !slices.Contains(SupportedTransportProtocols, c.Protocol) {
		errs = AppendError(errs, fmt.Errorf("invalid transport.protocol, optional values are %v", SupportedTransportProtocols))
	}
	if !slices.Contains(SupportedWireProtocols, c.WireProtocol) {
		errs = AppendError(errs, fmt.Errorf("invalid transport.wireProtocol, optional values are %v", SupportedWireProtocols))
	}
	return warnings, errs
}

View on GitHub (pinned to 6c8a8d0a97)

Solutions

  1. Set transport.tls.enable = true if you intend to use the configured certs
  2. Or remove transport.tls.certFile/keyFile/trustedCaFile entries to silence the warning
  3. Treat as non-fatal: frpc still starts, but TLS is genuinely disabled

Example fix

# before
[transport.tls]
certFile = "client.crt"
keyFile = "client.key"
# enable missing -> defaults false

# after
[transport.tls]
enable = true
certFile = "client.crt"
keyFile = "client.key"
Defensive patterns

Strategy: validation

Validate before calling

func tlsFieldsClean(c *v1.ClientTransportConfig) bool {
    if lo.FromPtr(c.TLS.Enable) {
        return true
    }
    return c.TLS.CertFile == "" && c.TLS.KeyFile == "" && c.TLS.TrustedCaFile == ""
}

Try / catch

if warn, _ := validation.ValidateClientCommonConfig(cfg); warn != nil {
    log.Printf("config warnings: %v", warn) // non-fatal; review TLS leftovers
}

Prevention

When it happens

Trigger: Client config contains transport.tls.certFile/keyFile/trustedCaFile paths while transport.tls.enable is false or omitted (defaults to false via lo.FromPtr on the pointer field).

Common situations: Disabling TLS temporarily (setting enable=false) while leaving cert paths in place; inheriting a shared config template that always includes TLS files; believing TLS is on by default.

Understand the failure class

Related errors


AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15). Data as JSON: /api/errors/c0e7db167208f044. Report an issue: GitHub.