fatedier/frp · error

ps.Err

Error message

ps.Err

What it means

Created with errors.New(ps.Err) in TunnelServer.waitProxyStatusReady (pkg/ssh/server.go:398). When an SSH-tunnel visitor (ssh tunnel gateway) requests a proxy, frpc polls the status exporter; if the proxy enters ProxyPhaseStartErr or ProxyPhaseClosed, the proxy's own error string is surfaced verbatim. The message is therefore dynamic — the real cause comes from the proxy that failed to start on the client side.

Source

Thrown at pkg/ssh/server.go:398

	defer ticker.Stop()

	timer := time.NewTimer(timeout)
	defer timer.Stop()

	statusExporter := s.vc.Service().StatusExporter()

	for {
		select {
		case <-ticker.C:
			ps, ok := statusExporter.GetProxyStatus(name)
			if !ok {
				continue
			}
			switch ps.Phase {
			case proxy.ProxyPhaseRunning:
				return ps, nil
			case proxy.ProxyPhaseStartErr, proxy.ProxyPhaseClosed:
				return ps, errors.New(ps.Err)
			}
		case <-timer.C:
			return nil, fmt.Errorf("wait proxy status ready timeout")
		case <-s.doneCh:
			return nil, fmt.Errorf("ssh tunnel server closed")
		}
	}
}

View on GitHub (pinned to 6c8a8d0a97)

Solutions

  1. Read the ps.Err content — it is the underlying proxy error (e.g. port bind failure); fix that root cause on the frpc side
  2. Check frpc logs for the named proxy to see why it entered start-err/closed
  3. Verify the remote port is free and the local service is reachable from frpc
  4. If it is a race at startup, retry the ssh forward once the proxy is Running
Defensive patterns

Strategy: retry

Try / catch

ps, err := tunnelServer.WaitProxyReady(name, timeout) // conceptual
if err != nil {
    if strings.Contains(err.Error(), "timeout") {
        // retry after confirming the proxy is registered
    }
    // ps.Err content names the real proxy failure; fix root cause on the frpc side
    return fmt.Errorf("proxy %s failed: %w", name, err)
}

Prevention

When it happens

Trigger: Using the frps ssh tunnel gateway (`frps --strict-ssh-tunnel` / ssh gateway port) to open a forward to a proxy whose client-side setup fails: port conflict on frpc host, unreachable local service, plugin exec failure, or auth/token rejection; proxy closes before reaching ProxyPhaseRunning.

Common situations: Remote port already bound on the frpc machine; local service behind the proxy down; token/auth mismatch between ssh session user and the frpc that owns the proxy; the 100ms polling observes StartErr shortly after NewProxy.

Related errors


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