fatedier/frp · error · ErrNoRouteFound

%v: %s %s %s

Error message

%v: %s %s %s

What it means

Vhost route-miss error from frp's HTTP vhost router: an incoming HTTP request's host, URL location, and HTTP user tuple matched no registered route. The message interpolates ErrNoRouteFound plus host, URL path and HTTPUser so you can see exactly what failed to match. In frps this typically becomes a 404 returned to the visitor.

Source

Thrown at pkg/util/vhost/http.go:184

}

// CreateConnection create a new connection by route config
func (rp *HTTPReverseProxy) CreateConnection(reqRouteInfo *RequestRouteInfo, byEndpoint bool) (net.Conn, error) {
	host, _ := httppkg.CanonicalHost(reqRouteInfo.Host)
	vr, ok := rp.vhostRouter.getByRoute(host, reqRouteInfo.URL, reqRouteInfo.HTTPUser)
	if ok {
		if byEndpoint {
			fn := vr.payload.(*RouteConfig).CreateConnByEndpointFn
			if fn != nil {
				return fn(reqRouteInfo.Endpoint, reqRouteInfo.RemoteAddr)
			}
		}
		fn := vr.payload.(*RouteConfig).CreateConnFn
		if fn != nil {
			return fn(reqRouteInfo.RemoteAddr)
		}
	}
	return nil, fmt.Errorf("%v: %s %s %s", ErrNoRouteFound, host, reqRouteInfo.URL, reqRouteInfo.HTTPUser)
}

func checkRouteAuthByRequest(req *http.Request, rc *RouteConfig) bool {
	if rc == nil {
		return true
	}
	if rc.Username == "" && rc.Password == "" {
		return true
	}

	if req.URL.Host != "" {
		proxyAuth := req.Header.Get("Proxy-Authorization")
		if proxyAuth == "" {
			return false
		}
		user, passwd, ok := httppkg.ParseBasicAuth(proxyAuth)
		return ok && user == rc.Username && passwd == rc.Password
	}

View on GitHub (pinned to 6c8a8d0a97)

Solutions

  1. Add the requested host to the frpc proxy: customDomains = ["app.example.com"] or subdomain = "app" (with subdomainHost = "example.com" in frps.toml)
  2. If locations are configured, ensure the request path falls under one, or remove locations to match all paths
  3. Confirm the Host header the client sends equals a registered domain (no port suffix issues; CanonicalHost is applied)
  4. Check routeByHTTPUser: the basic-auth user in the request must match the routed user

Example fix

# before (frps.toml has subdomainHost, frpc proxy has neither)
[[proxies]]
name = "web"
type = "http"
localPort = 8080

# after
[[proxies]]
name = "web"
type = "http"
localPort = 8080
subdomain = "app"
# request Host: app.example.com now matches
Defensive patterns

Strategy: validation

Validate before calling

// before pointing a domain at frps, confirm it will match a registered route
expected := "app.example.com"
_ = expected // ensure frpc proxy has customDomains=[expected] or subdomain="app" + subdomainHost="example.com"

Try / catch

body, err := io.ReadAll(resp.Body)
if err == nil && resp.StatusCode == 404 && strings.Contains(string(body), "no route found") {
    // host/location did not match any frpc proxy route: fix proxy config, not the client
}

Prevention

When it happens

Trigger: Request reaches frps's vhostHTTPPort with a Host header (domain/subdomain) that no frpc http/https proxy registered; correct domain but a URL path outside the proxy's configured locations; subdomain set but subdomainHost mismatch on the server; routeByHTTPUser configured and request lacking matching basic-auth user.

Common situations: DNS points to frps but the frpc proxy lacks customDomains/subdomains covering the requested host; subdomainHost not set (or set differently) in frps.toml so generated subdomains never match; wildcard expectations ('*.example.com') vs exact matching; proxy registered with locations = ["/foo"] while request hits /bar.

Related errors


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