fatedier/frp · error
ErrHealthCheckType
ErrHealthCheckType
Error message
error health check type
What it means
client/health's Monitor.doCheck returns ErrHealthCheckType when cfg.Type is neither 'tcp' nor 'http' (health.go:148). The health checker only implements TCP dial and HTTP GET probes; any other type string makes every check cycle fail, which drives statusFailedFn and marks the proxy unhealthy.
Source
Thrown at client/health/health.go:31
// limitations under the License.
package health
import (
"context"
"errors"
"fmt"
"io"
"net"
"net/http"
"strings"
"time"
v1 "github.com/fatedier/frp/pkg/config/v1"
"github.com/fatedier/frp/pkg/util/xlog"
)
var ErrHealthCheckType = errors.New("error health check type")
type Monitor struct {
checkType string
interval time.Duration
timeout time.Duration
maxFailedTimes int
// For tcp
addr string
// For http
url string
header http.Header
failedTimes uint64
statusOK bool
statusNormalFn func()
statusFailedFn func()
View on GitHub (pinned to 6c8a8d0a97)
Solutions
- Set healthCheck.type to exactly 'tcp' or 'http' in the proxy config
- For HTTPS targets use type 'http' — the checker does a plain HTTP request to the given path/port
- Remove the healthCheck block entirely if no probe is wanted
- After fixing, reload frpc so a new Monitor is built from the corrected config
Example fix
# before [[proxies]] name = "web" healthCheck.type = "https" # -> ErrHealthCheckType every cycle # after [[proxies]] name = "web" healthCheck.type = "http" healthCheck.path = "/healthz"
Defensive patterns
Strategy: validation
Validate before calling
func validHealthCheckType(t string) bool { return t == "" || t == "tcp" || t == "http" }
if !validHealthCheckType(cfg.HealthCheck.Type) {
return fmt.Errorf("healthCheck.type must be tcp or http, got %q", cfg.HealthCheck.Type)
} Try / catch
err := monitor.DoCheck(ctx)
if errors.Is(err, health.ErrHealthCheckType) {
// permanent misconfiguration — disable the monitor rather than counting failures
monitor.Stop()
} Prevention
- Whitelist type to tcp/http in config linting before deploy
- Remember 'https' targets use type 'http'
- Health-check config errors are permanent: fail validation at load time, not per-tick
When it happens
Trigger: A proxy config with healthCheck.type set to something other than tcp/http (e.g. 'https', 'grpc', 'udp', or a typo like 'TCP' with different casing depending on validation) — each checkWorker tick calls doCheck and gets this error, so the proxy is reported failed after maxFailed times.
Common situations: Copying a healthCheck block from another tool that supports more probe types; assuming 'https' works because the URL scheme exists; case or whitespace differences in the type string.
Related errors
AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15).
Data as JSON: /api/errors/a2d67233a206ecfd.
Report an issue: GitHub.