{"record":{"id":"af107d00a52735c1","repo":"XTLS/Xray-core","slug":"bad-login-finished-packet-id-d","errorCode":null,"errorMessage":"bad login finished packet id: %d","messagePattern":"bad login finished packet id: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"transport/internet/finalmask/xmc/client.go","lineNumber":206,"sourceCode":"\n\tc.writer, err = newCryptoWriter(c.writer, sharedSecret)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"new crypto writer: %w\", err)\n\t}\n\n\tpkt, err = readPacket(c.reader)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"read login finished: %w\", err)\n\t}\n\tif pkt.packetID == 0x00 {\n\t\tvar reason String\n\t\tif readErr := pkt.readFields(&reason); readErr != nil {\n\t\t\treturn fmt.Errorf(\"authentication rejected\")\n\t\t}\n\t\treturn fmt.Errorf(\"authentication rejected: %s\", reason)\n\t}\n\tif pkt.packetID != 0x02 {\n\t\treturn fmt.Errorf(\"bad login finished packet id: %d\", pkt.packetID)\n\t}\n\n\treceivedProfile, err := readLoginSuccess(pkt)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"read login finished fields: %w\", err)\n\t}\n\tif receivedProfile != selectedProfile {\n\t\treturn fmt.Errorf(\"login profile mismatch\")\n\t}\n\tloginAcknowledgedLength, err := writePacketWithLength(c.writer, 0x03)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"write login acknowledged: %w\", err)\n\t}\n\tif err = runPaddingSchedule(c.reader, c.writer, true, loginAcknowledgedLength, c.paddingSchedule); err != nil {\n\t\treturn fmt.Errorf(\"run startup padding: %w\", err)\n\t}\n\n\tpacket := newPacketStream(c.reader, c.writer, true)","sourceCodeStart":188,"sourceCodeEnd":224,"githubUrl":"https://github.com/XTLS/Xray-core/blob/7d214f8b094f75322fa3990f8aadad1c912f24f5/transport/internet/finalmask/xmc/client.go#L188-L224","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// before connecting, verify both ends run the same xmc build\nif clientBuildVersion != serverBuildVersion {\n    return fmt.Errorf(\"xmc version skew: client %s vs server %s\", clientBuildVersion, serverBuildVersion)\n}","typeGuard":null,"tryCatchPattern":"_, err := conn.Read(buf)\nif err != nil && strings.Contains(err.Error(), \"bad login finished packet id\") {\n    return fmt.Errorf(\"protocol mismatch: endpoint is not a matching xmc server\")\n}","preventionTips":["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"],"tags":["protocol","version-mismatch","handshake","go"],"backgroundTag":null,"analyzedSha":"7d214f8b094f75322fa3990f8aadad1c912f24f5","analyzedAt":"2026-08-15T14:26:24.325Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}