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

  1. Make auth.token byte-identical in frpc.toml and frps.toml (watch for trailing whitespace)
  2. Read the exact server message — it usually states the precise reason (token, version, limit)
  3. Confirm both sides are compatible frp versions
  4. 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

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


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