fatedier/frp · error · ErrNoRouteFound

no route found

Error message

no route found

What it means

ErrNoRouteFound is the sentinel for the vhost HTTP router: the reverse proxy in pkg/util/vhost/http.go found no registered route matching the request. At the return site it is wrapped with host, URL and HTTP user ('no route found: host url user') so you can see exactly which dimensions failed to match. Routes are added by frps when HTTP/HTTPS-type proxies register their domain/location.

Source

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

	"context"
	"encoding/base64"
	"errors"
	"fmt"
	stdlog "log"
	"net"
	"net/http"
	"net/http/httputil"
	"net/url"
	"time"

	libio "github.com/fatedier/golib/io"
	"github.com/fatedier/golib/pool"

	httppkg "github.com/fatedier/frp/pkg/util/http"
	"github.com/fatedier/frp/pkg/util/log"
)

var ErrNoRouteFound = errors.New("no route found")

type HTTPReverseProxyOptions struct {
	ResponseHeaderTimeoutS int64
}

type HTTPReverseProxy struct {
	proxy       http.Handler
	vhostRouter *Routers

	responseHeaderTimeout time.Duration
}

func NewHTTPReverseProxy(option HTTPReverseProxyOptions, vhostRouter *Routers) *HTTPReverseProxy {
	if option.ResponseHeaderTimeoutS <= 0 {
		option.ResponseHeaderTimeoutS = 60
	}
	rp := &HTTPReverseProxy{
		responseHeaderTimeout: time.Duration(option.ResponseHeaderTimeoutS) * time.Second,

View on GitHub (pinned to 6c8a8d0a97)

Solutions

  1. Match the request Host header exactly to a proxy's customDomains or group.subdomain + frps subdomainHost
  2. Confirm the frpc owning the HTTP proxy is connected and the proxy reached Running state
  3. If using subdomains, set subdomainHost on frps and use subdomain = "x" so x.subdomainHost resolves
  4. For multi-location proxies, check the request path matches one of the configured locations (prefix match)

Example fix

# before (frpc.toml) — domain typo'd
[[proxies]]
name = "web"
type = "http"
remotePort = 80
customDomains = ["exmaple.com"]

# after
customDomains = ["example.com"]
Defensive patterns

Strategy: validation

Validate before calling

// Before sending traffic, confirm a route exists (frps side)
if _, err := vhostRouter.Get(host, routePath, httpUser); errors.Is(err, vhost.ErrNoRouteFound) {
    // no proxy registered for this host/path/user yet — register or fix the Host header
}

Type guard

func isNoRouteFound(err error) bool {
    return errors.Is(err, vhost.ErrNoRouteFound)
}

Try / catch

if err := proxy.ServeHTTP(w, r); err != nil {
    if errors.Is(err, vhost.ErrNoRouteFound) {
        http.Error(w, "unknown vhost route — check proxy domain/location", http.StatusNotFound)
        return
    }
    http.Error(w, err.Error(), http.StatusBadGateway)
}

Prevention

When it happens

Trigger: Browsing to a host:port served by frps vhostHTTPPort before any matching proxy is registered; wrong Host header (domain not configured in any proxy's customDomains/subdomain); location path not matching any proxy's locations; vhostHTTPPassword/HTTPUser mismatch when basic-auth vhost is enabled.

Common situations: DNS points to the frps server but the frpc proxy with that customDomain is offline; subdomain configured but subdomainHost not set on frps (so the full host never matches); typo in domain; requests arriving with a port appended to Host (host:8080) not matching; proxy registered under a different httpUser.

Related errors


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