{"record":{"id":"266186096e9c6da3","repo":"fatedier/frp","slug":"invalid-heartbeat-timeout-heartbeat-timeout-is-le","errorCode":null,"errorMessage":"invalid heartbeat_timeout, heartbeat_timeout is less than heartbeat_interval","messagePattern":"invalid heartbeat_timeout, heartbeat_timeout is less than heartbeat_interval","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/config/legacy/client.go","lineNumber":365,"sourceCode":"// values of the new configuration.\nfunc GetDefaultClientConf() ClientCommonConf {\n\treturn ClientCommonConf{\n\t\tClientConfig:              legacyauth.GetDefaultClientConf(),\n\t\tTCPMux:                    true,\n\t\tLoginFailExit:             true,\n\t\tProtocol:                  \"tcp\",\n\t\tStart:                     make([]string, 0),\n\t\tTLSEnable:                 true,\n\t\tDisableCustomTLSFirstByte: true,\n\t\tMetas:                     make(map[string]string),\n\t\tIncludeConfigFiles:        make([]string, 0),\n\t}\n}\n\nfunc (cfg *ClientCommonConf) Validate() error {\n\tif cfg.HeartbeatTimeout > 0 && cfg.HeartbeatInterval > 0 {\n\t\tif cfg.HeartbeatTimeout < cfg.HeartbeatInterval {\n\t\t\treturn fmt.Errorf(\"invalid heartbeat_timeout, heartbeat_timeout is less than heartbeat_interval\")\n\t\t}\n\t}\n\n\tif !cfg.TLSEnable {\n\t\tif cfg.TLSCertFile != \"\" {\n\t\t\tfmt.Println(\"WARNING! tls_cert_file is invalid when tls_enable is false\")\n\t\t}\n\n\t\tif cfg.TLSKeyFile != \"\" {\n\t\t\tfmt.Println(\"WARNING! tls_key_file is invalid when tls_enable is false\")\n\t\t}\n\n\t\tif cfg.TLSTrustedCaFile != \"\" {\n\t\t\tfmt.Println(\"WARNING! tls_trusted_ca_file is invalid when tls_enable is false\")\n\t\t}\n\t}\n\n\tif !slices.Contains([]string{\"tcp\", \"kcp\", \"quic\", \"websocket\", \"wss\"}, cfg.Protocol) {","sourceCodeStart":347,"sourceCodeEnd":383,"githubUrl":"https://github.com/fatedier/frp/blob/6c8a8d0a97d03b44e9528d30b30c70cb9d61b405/pkg/config/legacy/client.go#L347-L383","documentation":"This error comes from ClientCommonConf.Validate in the legacy INI frpc config parser. It rejects a [common] section where both heartbeat_interval and heartbeat_timeout are set to positive values but heartbeat_timeout is smaller than heartbeat_interval. Since the timeout must give the heartbeat enough time to arrive, a timeout shorter than the interval is logically invalid.","triggerScenarios":"A legacy INI frpc.ini containing e.g. heartbeat_interval = 10 and heartbeat_timeout = 3. Both values must be > 0 for the check to run; if either is 0 (unset), validation is skipped.","commonSituations":"Users copying heartbeat examples from old tutorials, or tuning heartbeat_interval up (e.g. to reduce traffic) while leaving an old heartbeat_timeout in place; also seen after migrating configs between frp versions where defaults changed (defaults are interval 30 / timeout 90).","solutions":["Set heartbeat_timeout to at least heartbeat_interval (conventionally 3x, e.g. interval=30, timeout=90)","Or remove heartbeat_timeout entirely and let frpc apply its default (90s), which is already > the default interval","If migrating to the new TOML/YAML format, use transport.heartbeatInterval and transport.heartbeatTimeout with correct ordering"],"exampleFix":"# before\n[common]\nheartbeat_interval = 10\nheartbeat_timeout = 3\n\n# after\n[common]\nheartbeat_interval = 10\nheartbeat_timeout = 30","handlingStrategy":"validation","validationCode":"// before calling load: check INI values\niv, _ := strconv.Atoi(common.HeartbeatInterval)\ntv, _ := strconv.Atoi(common.HeartbeatTimeout)\nif tv > 0 && iv > 0 && tv < iv {\n    return fmt.Errorf(\"heartbeat_timeout (%d) must be >= heartbeat_interval (%d)\", tv, iv)\n}","typeGuard":"func validHeartbeat(interval, timeout int) bool {\n    return timeout == 0 || interval == 0 || timeout >= interval\n}","tryCatchPattern":"if err := legacy.LoadConfigureFromFile(path, ...); err != nil { if strings.Contains(err.Error(), \"invalid heartbeat_timeout\") { /* fix interval/timeout values, notify operator */ } return err }","preventionTips":["Always derive heartbeat_timeout from heartbeat_interval (e.g. 3x) in config templates","Run `frpc verify -c frpc.ini` in CI before deploy","Prefer the new TOML format and set transport.heartbeatTimeout explicitly"],"tags":["config","validation","heartbeat","legacy-ini","frpc"],"backgroundTag":null,"analyzedSha":"6c8a8d0a97d03b44e9528d30b30c70cb9d61b405","analyzedAt":"2026-08-15T06:53:27.215Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}