fatedier/frp · error
start new visitor connection error: %s
Error message
start new visitor connection error: %s
What it means
The server answered the visitor's connection request with an explicit error string inside NewVisitorConnResp.Error. This is a server-side rejection, not a local failure: frps validated the request (proxy lookup, signature, negotiation) and refused it; the message string is the server's reason.
Source
Thrown at client/visitor/visitor.go:198
}
err = visitorConn.WriteMsg(newVisitorConnMsg)
if err != nil {
visitorConn.Close()
return nil, fmt.Errorf("send newVisitorConnMsg to server error: %v", err)
}
_ = visitorConn.SetReadDeadline(time.Now().Add(10 * time.Second))
var newVisitorConnRespMsg msg.NewVisitorConnResp
err = visitorConn.ReadMsgInto(&newVisitorConnRespMsg)
if err != nil {
visitorConn.Close()
return nil, fmt.Errorf("read newVisitorConnRespMsg error: %v", err)
}
_ = visitorConn.SetReadDeadline(time.Time{})
if newVisitorConnRespMsg.Error != "" {
visitorConn.Close()
return nil, fmt.Errorf("start new visitor connection error: %s", newVisitorConnRespMsg.Error)
}
return visitorConn, nil
}
func wrapVisitorConn(conn io.ReadWriteCloser, cfg *v1.VisitorBaseConfig) (io.ReadWriteCloser, func(), error) {
rwc := conn
if cfg.Transport.UseEncryption {
var err error
rwc, err = libio.WithEncryption(rwc, []byte(cfg.SecretKey))
if err != nil {
return nil, func() {}, fmt.Errorf("create encryption stream error: %v", err)
}
}
recycleFn := func() {}
if cfg.Transport.UseCompression {
rwc, recycleFn = libio.WithCompressionFromPool(rwc)
}
return rwc, recycleFn, nilView on GitHub (pinned to 6c8a8d0a97)
Solutions
- Compare the visitor's serverName with the frpc proxy name it targets; they must match exactly.
- Verify the same secretKey (and auth token/user) is configured on the visitor, the proxy owner, and frps.
- Sync clocks via NTP on client and server so the auth timestamp stays within tolerance.
- In multi-user setups, check that the user/serverUser prefix logic produces the proxy name the server actually registered.
Example fix
# frpc visitor config (TOML) # before [[visitors]] name = "ssh-v" type = "stcp" serverName = "ssh-wrong" secretKey = "abc" # after [[visitors]] name = "ssh-v" type = "stcp" serverName = "ssh" # must equal the owner's proxy name secretKey = "abc" # must equal the proxy's secretKey
Defensive patterns
Strategy: validation
Validate before calling
// Before starting the visitor, sanity-check the name it will target base := visitorCfg.GetBaseConfig() target := naming.BuildTargetServerProxyName(user, base.ServerUser, base.ServerName) _ = target // cross-check against the registered proxy names of the owner client
Try / catch
if _, err := v.newVisitorConn(ctx); err != nil {
if strings.Contains(err.Error(), "start new visitor connection error") {
// server rejection: config problem — do NOT retry blindly; fix name/key
return err
}
} Prevention
- Keep visitor serverName identical to the owner proxy name
- Share secretKey via one source of truth across owner, visitor, and server
- Sync clocks with NTP on all frp hosts
When it happens
Trigger: Target proxy name not found on the server (the name built from user/serverUser/serverName has no matching stcp/xtcp proxy); SignKey mismatch because the visitor's secretKey differs from the server; timestamp skew beyond the allowed window; the target proxy does not accept visitors.
Common situations: Visitor's serverName does not match the proxy name of the serving frpc; visitor and server disagree on secretKey/auth token; client and server clocks drift so the timestamped signature is rejected; multi-user prefixes (user/serverUser) produce a name that differs from the registered proxy name.
Related errors
- visitor plugin type is empty
- auth.oidc.clientID is required; auth.oidc.tokenEndpointURL i
- name is required
- server name is required
- bind port is required
AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15).
Data as JSON: /api/errors/1d1aed9553b8c762.
Report an issue: GitHub.