fatedier/frp · error

open ssh channel error: %v

Error message

open ssh channel error: %v

What it means

Emitted by TunnelServer.openConn when the server cannot open a ChannelTypeServerOpenChannel back over the SSH connection to the visitor's client. For remote-visited traffic, data flows through a second SSH channel opened by frps toward the client; if the client rejects or the connection is dead, this error surfaces on the visitor's connection path.

Source

Thrown at pkg/ssh/server.go:370

				return
			}
		case <-s.doneCh:
			return
		}
	}
}

func (s *TunnelServer) openConn(addr *tcpipForward) (net.Conn, error) {
	payload := forwardedTCPPayload{
		Addr: addr.Host,
		Port: addr.Port,
		// Note: Here is just for compatibility, not the real source address.
		OriginAddr: addr.Host,
		OriginPort: addr.Port,
	}
	channel, reqs, err := s.sshConn.OpenChannel(ChannelTypeServerOpenChannel, ssh.Marshal(&payload))
	if err != nil {
		return nil, fmt.Errorf("open ssh channel error: %v", err)
	}
	go ssh.DiscardRequests(reqs)

	conn := netpkg.WrapReadWriteCloserToConn(channel, s.underlyingConn)
	return conn, nil
}

func (s *TunnelServer) waitProxyStatusReady(name string, timeout time.Duration) (*proxy.WorkingStatus, error) {
	ticker := time.NewTicker(100 * time.Millisecond)
	defer ticker.Stop()

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

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

	for {
		select {

View on GitHub (pinned to 6c8a8d0a97)

Solutions

  1. Confirm the frp SSH tunnel client is still connected and healthy (frps dashboard / logs).
  2. Have the visitor retry the connection — transient races during client reconnect resolve themselves.
  3. Keep the gateway-client connection alive with SSH keepalives/heartbeat settings so NATs do not kill it silently.
  4. If it persists, check client-side logs for channel-open rejections and raise channel limits if a custom SSH stack is in play.
Defensive patterns

Strategy: retry

Try / catch

// visitor-side retry with backoff when a channel open fails
var conn net.Conn
err := retry.Do(
    func() error {
        var e error
        conn, e = dialVisitor()
        return e
    },
    retry.OnError(func(err error) bool {
        return strings.Contains(err.Error(), "open ssh channel error")
    }),
    retry.Attempts(3), retry.Delay(500*time.Millisecond),
)

Prevention

When it happens

Trigger: Client disconnected or is shutting down right as a visitor connects; client's SSH implementation rejects the channel open; too many open channels exhausting SSH channel windows; underlying TCP connection reset between gateway and tunnel client.

Common situations: Visitor traffic racing client shutdown/restart; NAT idle timeouts killing the SSH connection while the gateway still routes to it; resource-exhausted clients dropping new channels.

Related errors


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