fatedier/frp · error
xtcp server for [%s] doesn't exist
Error message
xtcp server for [%s] doesn't exist
What it means
Thrown in the nathole Controller's visitor-message handler (pkg/nathole/controller.go) when a NatHoleVisitor message arrives for a proxy name that has no registered xtcp client configuration. The controller looks up c.clientCfgs[m.ProxyName] under lock; a miss means no client-side xtcp server is currently registered under that name, so hole punching cannot proceed and the error is sent back to the visitor inside a NatHoleResp.
Source
Thrown at pkg/nathole/controller.go:187
sid := c.GenSid()
session := &Session{
sid: sid,
visitorMsg: m,
visitorTransporter: transporter,
notifyCh: make(chan struct{}, 1),
}
var (
clientCfg *ClientCfg
ok bool
)
err := func() error {
c.mu.Lock()
defer c.mu.Unlock()
clientCfg, ok = c.clientCfgs[m.ProxyName]
if !ok {
return fmt.Errorf("xtcp server for [%s] doesn't exist", m.ProxyName)
}
if !util.ConstantTimeEqString(m.SignKey, util.GetAuthKey(clientCfg.sk, m.Timestamp)) {
return fmt.Errorf("xtcp connection of [%s] auth failed", m.ProxyName)
}
c.sessions[sid] = session
return nil
}()
if err != nil {
log.Warnf("handle visitorMsg error: %v", err)
_ = transporter.Send(c.GenNatHoleResponse(m.TransactionID, nil, err.Error()))
return
}
log.Tracef("handle visitor message, sid [%s], server name: %s", sid, m.ProxyName)
defer func() {
c.mu.Lock()
defer c.mu.Unlock()
delete(c.sessions, sid)View on GitHub (pinned to 6c8a8d0a97)
Solutions
- Set the visitor's serverName in frpc.toml to exactly the client's xtcp proxy name
- Verify the client owning the xtcp proxy is connected and its proxy registered successfully (check frps dashboard/logs)
- Retry from the visitor once the client is confirmed online
- Check for typos and whitespace differences in proxy names between the two configs
Example fix
# before (visitor config, wrong target) [[visitors]] name = "p2p-v" type = "xtcp" serverName = "p2p-others" # after [[visitors]] name = "p2p-v" type = "xtcp" serverName = "p2p" # must equal the client's xtcp proxy name
Defensive patterns
Strategy: validation
Try / catch
if err := nathole.PreCheck(ctx, tp, proxyName, timeout); err != nil {
if strings.Contains(err.Error(), "doesn't exist") {
// client not registered yet: verify serverName, wait for client, retry
}
return err
} Prevention
- Visitor's serverName must exactly equal the client's xtcp proxy name
- Run PreCheck before dialing to fail fast
- Confirm the client's proxy is registered (frps logs/dashboard) before visiting
When it happens
Trigger: A visitor sends a NatHoleVisitor message for proxyName that was never registered via ListenClient, or whose registration was removed (client disconnected / CloseClient called) before the visitor's request arrived.
Common situations: Visitor config's serverName does not match the client's xtcp proxy name; the frpc hosting the xtcp proxy is offline or has not yet registered when the visitor connects; the client disconnected between registration and the visitor's punch attempt.
Related errors
- proxy [%s] is repeated
- xtcp connection of [%s] auth failed
- %s
- classify visitor nat feature error: %v
- no external address found
AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15).
Data as JSON: /api/errors/d97227c0fb983fb4.
Report an issue: GitHub.