fatedier/frp · error
loginRespMsg.Error
Error message
loginRespMsg.Error
What it means
During frpc→frps login, the server's LoginResp message carries an Error string for rejections; control_session.go turns any non-empty value into the dial error. This is frps actively refusing the client after parsing its Login message — the error text comes straight from the server (e.g. token mismatch), unlike network-level dial failures which error earlier in exchangeLogin.
Source
Thrown at client/control_session.go:83
}
defer func() {
if !success {
_ = conn.Close()
}
}()
loginMsg, err := d.buildLoginMsg(previousRunID)
if err != nil {
return nil, err
}
loginResult, err := d.exchangeLogin(conn, loginMsg)
if err != nil {
return nil, err
}
loginRespMsg := loginResult.resp
if loginRespMsg.Error != "" {
return nil, errors.New(loginRespMsg.Error)
}
var controlRW io.ReadWriter = conn
if d.clientSpec == nil || d.clientSpec.Type != "ssh-tunnel" {
controlRW, err = d.newControlReadWriter(conn, loginResult.crypto)
if err != nil {
return nil, fmt.Errorf("create control crypto read writer: %w", err)
}
}
success = true
return &SessionContext{
Common: d.common,
RunID: loginRespMsg.RunID,
Conn: msg.NewConn(conn, msg.NewReadWriter(controlRW, d.common.Transport.WireProtocol)),
Auth: d.auth,
Connector: newMessageConnector(connector, d.common.Transport.WireProtocol),
VnetController: d.vnetController,View on GitHub (pinned to 6c8a8d0a97)
Solutions
- Make auth.token byte-identical in frpc.toml and frps.toml (watch for trailing whitespace)
- Read the exact server message — it usually states the precise reason (token, version, limit)
- Confirm both sides are compatible frp versions
- Check frps logs for the login attempt to see the server-side view
Example fix
# before (frpc.toml) auth: token = "s3cret! " # trailing space -> server rejects # after auth: token = "s3cret!"
Defensive patterns
Strategy: try-catch
Validate before calling
// Before dialing, compare configured token presence with expectations
if len(svr.cfg.Auth.Token) == 0 && svr.cfg.Auth.Method != "" {
log.Warn("empty auth.token — many frps setups reject tokenless logins")
} Try / catch
sess, err := dialer.Dial(ctx)
if err != nil {
// LoginResp.Error surfaces here verbatim; retrying is pointless until config matches
log.Errorf("frps rejected login: %v (check auth.token/version)", err)
return err
} Prevention
- Manage auth.token via a single shared secret source for frps and all frpcs
- Don't auto-retry login failures — they are deterministic rejections, not transient errors
- Log the server's message; it distinguishes token vs version vs policy rejections
When it happens
Trigger: Login with auth.token not matching frps's token; server running a different version with incompatible login semantics; server at max connections or refusing the user; TLS/multiplexing settings that make frps reject the session at the application layer.
Common situations: auth.token typo'd or rotated on one side only after a restart; pointing frpc at an frps that requires authentication while the client config has none; mixed old/new frp versions during an upgrade window.
Related errors
- login to the server failed: %v. With loginFailExit enabled,
- ErrInvalidArgument
- ErrNotFound
- ErrConflict
- ErrStoreDisabled
AI-assisted analysis of fatedier/frp@6c8a8d0a97 (2026-08-15).
Data as JSON: /api/errors/0dd5597c221557d9.
Report an issue: GitHub.