{"record":{"id":"8784f3392f9b2480","repo":"XTLS/Xray-core","slug":"write-packet-bad-length-d","errorCode":null,"errorMessage":"write packet: bad length: %d","messagePattern":"write packet: bad length: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"transport/internet/finalmask/xmc/protocol.go","lineNumber":404,"sourceCode":"\t\treturn 0, err\n\t}\n\tif err = writeFull(w, frame); err != nil {\n\t\treturn 0, fmt.Errorf(\"write packet data: %w\", err)\n\t}\n\treturn len(frame), nil\n}\n\nfunc encodePacket(packetID int, fields ...field) ([]byte, error) {\n\tvar dataBuf bytes.Buffer\n\n\tfor _, field := range fields {\n\t\terr := field.writeTo(&dataBuf)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"write packet field: %w\", err)\n\t\t}\n\t}\n\tif dataBuf.Len() > maxPacketDataLength {\n\t\treturn nil, fmt.Errorf(\"write packet: bad length: %d\", dataBuf.Len())\n\t}\n\n\tpacketIDVarint := Varint(packetID)\n\tbodyLength := varintSize(packetIDVarint) + dataBuf.Len()\n\tif bodyLength > maxPacketBodyLength {\n\t\treturn nil, fmt.Errorf(\"write packet: bad length: %d\", bodyLength)\n\t}\n\n\tvar frame bytes.Buffer\n\tframe.Grow(varintSize(Varint(bodyLength)) + bodyLength)\n\tframeLength := Varint(bodyLength)\n\tif err := frameLength.writeTo(&frame); err != nil {\n\t\treturn nil, fmt.Errorf(\"write packet length: %w\", err)\n\t}\n\tif err := packetIDVarint.writeTo(&frame); err != nil {\n\t\treturn nil, fmt.Errorf(\"write packet ID: %w\", err)\n\t}\n\tframe.Write(dataBuf.Bytes())","sourceCodeStart":386,"sourceCodeEnd":422,"githubUrl":"https://github.com/XTLS/Xray-core/blob/7d214f8b094f75322fa3990f8aadad1c912f24f5/transport/internet/finalmask/xmc/protocol.go#L386-L422","documentation":"encodePacket rejects an outgoing packet whose encoded field data exceeds maxPacketDataLength (32 KiB, protocol.go:11). This is a hard cap on the Minecraft protocol frame body this transport will emit, guarding the framing layer from oversized packets. It fires before the packet ID is prepended and before framing.","triggerScenarios":"Calling writePacket with fields whose combined serialized size exceeds 32768 bytes, e.g. writing the login-finished success packet with a very large textures value/signature (profile.TexturesValue/TexturesSignature) or an oversized status JSON string.","commonSituations":"Injecting a login profile whose base64 textures property is larger than 32 KiB; hand-edited or machine-generated profiles from config. Vanilla servers keep textures well under this limit, so seeing it usually means misconfigured profile data.","solutions":["Check the wrapped length in the message and identify which field (usually profile textures) exceeds 32 KiB","Shorten or omit the textures property in the configured login profile (empty TexturesValue/TexturesSignature)","If genuinely large payloads are required, raise maxPacketDataLength in a fork — but note vanilla clients may reject such frames","Validate profile sizes at config load time instead of at connection time"],"exampleFix":"// before\nprofile := loginProfile{TexturesValue: hugeBase64} // > 32 KiB\n\n// after\nprofile := loginProfile{} // omit textures; empty value stays within the frame cap","handlingStrategy":"validation","validationCode":"const maxFieldBudget = 32 * 1024\\nif len(profile.TexturesValue)+len(profile.TexturesSignature) > maxFieldBudget-1024 {\\n\\treturn fmt.Errorf(\"login profile textures too large: %d bytes\", len(profile.TexturesValue)+len(profile.TexturesSignature))\\n}","typeGuard":"func profileFitsPacket(p loginProfile) bool {\\n\\treturn len(p.TexturesValue)+len(p.TexturesSignature) < 30*1024\\n}","tryCatchPattern":"if err := writePacket(w, 0x02, fields...); err != nil {\\n\\tvar maxErr *maxPacketError\\n\\tif errors.As(err, &maxErr) || strings.Contains(err.Error(), \"bad length\") {\\n\\t\\t// shrink payload (drop textures) and retry once\\n\\t}\\n}","preventionTips":["Validate login profile texture sizes at config load, not per connection","Keep status JSON and any custom strings well under 32 KiB","Add unit tests asserting every packet you construct stays under maxPacketDataLength"],"tags":["go","minecraft-protocol","packet-size","validation","xmc"],"backgroundTag":null,"analyzedSha":"7d214f8b094f75322fa3990f8aadad1c912f24f5","analyzedAt":"2026-08-15T14:26:24.325Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}