XTLS/Xray-core · error
bad login finished packet id: %d
Error message
bad login finished packet id: %d
What it means
After encryption, the server sent a login-state packet whose ID is neither 0x00 (disconnect) nor 0x02 (Login Success). The handshake state machine only accepts those two IDs at this point, so any other ID (e.g. 0x03 Login Acknowledged, 0x04/0x05 compression or plugin packets) is a protocol violation or version skew.
Source
Thrown at transport/internet/finalmask/xmc/client.go:206
c.writer, err = newCryptoWriter(c.writer, sharedSecret)
if err != nil {
return fmt.Errorf("new crypto writer: %w", err)
}
pkt, err = readPacket(c.reader)
if err != nil {
return fmt.Errorf("read login finished: %w", err)
}
if pkt.packetID == 0x00 {
var reason String
if readErr := pkt.readFields(&reason); readErr != nil {
return fmt.Errorf("authentication rejected")
}
return fmt.Errorf("authentication rejected: %s", reason)
}
if pkt.packetID != 0x02 {
return fmt.Errorf("bad login finished packet id: %d", pkt.packetID)
}
receivedProfile, err := readLoginSuccess(pkt)
if err != nil {
return fmt.Errorf("read login finished fields: %w", err)
}
if receivedProfile != selectedProfile {
return fmt.Errorf("login profile mismatch")
}
loginAcknowledgedLength, err := writePacketWithLength(c.writer, 0x03)
if err != nil {
return fmt.Errorf("write login acknowledged: %w", err)
}
if err = runPaddingSchedule(c.reader, c.writer, true, loginAcknowledgedLength, c.paddingSchedule); err != nil {
return fmt.Errorf("run startup padding: %w", err)
}
packet := newPacketStream(c.reader, c.writer, true)View on GitHub (pinned to 7d214f8b09)
Solutions
- Confirm the destination is the paired xmc server, not a vanilla Minecraft server
- Use matching client/server builds of the finalmask/xmc package
- Check the server's protocol version handling around login; packet 0x01 here usually means the server tried a second Encryption Request
- Report upstream if both sides are the same version and it persists
Defensive patterns
Strategy: validation
Validate before calling
// before connecting, verify both ends run the same xmc build
if clientBuildVersion != serverBuildVersion {
return fmt.Errorf("xmc version skew: client %s vs server %s", clientBuildVersion, serverBuildVersion)
} Try / catch
_, err := conn.Read(buf)
if err != nil && strings.Contains(err.Error(), "bad login finished packet id") {
return fmt.Errorf("protocol mismatch: endpoint is not a matching xmc server")
} Prevention
- Pin identical versions of the finalmask/xmc package on client and server
- Point outbounds only at xmc-compatible endpoints, never vanilla Minecraft servers
- Add an integration test asserting the full handshake between shipped builds
When it happens
Trigger: First Read/Write on the wrapped conn when the server runs a different protocol/handshake ordering than this client expects (protocol version 775 hardcoded at client.go:84), or a non-xmc/genuine Minecraft server responded because the port points at vanilla software.
Common situations: Pointing the outbound at a plain Minecraft server instead of the xmc-compatible endpoint; server or client built from mismatched finalmask/xmc versions; a proxy in front injecting extra login packets.
Related errors
- read login finished fields: %w
- authentication rejected
- run startup padding: %w
- empty domain name
- unknown Socks version: {version}
AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15).
Data as JSON: /api/errors/af107d00a52735c1.
Report an issue: GitHub.