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
- Set transport.tls.enable = true if you intend to use the configured certs
- Or remove transport.tls.certFile/keyFile/trustedCaFile entries to silence the warning
- 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
- Remove TLS material whenever disabling tls.enable instead of leaving it
- Monitor warnings in startup logs, not just errors
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
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- invalid transport.heartbeatTimeout, heartbeat timeout should
- invalid transport.protocol, optional values are %v
- invalid transport.wireProtocol, optional values are %v
- tls.certFile must be specified when tls is enabled
- tls.keyFile must be specified when tls is enabled
AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15).
Data as JSON: /api/errors/c0e7db167208f044.
Report an issue: GitHub.