{"record":{"id":"2e38987bf15ccb96","repo":"XTLS/Xray-core","slug":"customtable-produced-empty-padding-pool","errorCode":null,"errorMessage":"customTable produced empty padding pool","messagePattern":"customTable produced empty padding pool","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"transport/internet/finalmask/sudoku/table.go","lineNumber":341,"sourceCode":"\tpaddingSet := make(map[byte]struct{}, 64)\n\tpadding := make([]byte, 0, 64)\n\tfor drop := range xBits {\n\t\tfor val := byte(0); val < 4; val++ {\n\t\t\tfor pos := byte(0); pos < 16; pos++ {\n\t\t\t\tgroup := (val << 4) | pos\n\t\t\t\tb := encodeGroupWithDropX(group, drop)\n\t\t\t\tif bits.OnesCount8(b) >= 5 {\n\t\t\t\t\tif _, exists := paddingSet[b]; !exists {\n\t\t\t\t\t\tpaddingSet[b] = struct{}{}\n\t\t\t\t\t\tpadding = append(padding, b)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tsort.Slice(padding, func(i, j int) bool { return padding[i] < padding[j] })\n\tif len(padding) == 0 {\n\t\treturn nil, fmt.Errorf(\"customTable produced empty padding pool\")\n\t}\n\n\tdecodeGroup := func(b byte) (byte, bool) {\n\t\tif (b & xMask) != xMask {\n\t\t\treturn 0, false\n\t\t}\n\n\t\tvar val, pos byte\n\t\tif b&(1<<pBits[0]) != 0 {\n\t\t\tval |= 0x02\n\t\t}\n\t\tif b&(1<<pBits[1]) != 0 {\n\t\t\tval |= 0x01\n\t\t}\n\t\tfor i, bit := range vBits {\n\t\t\tif b&(1<<bit) != 0 {\n\t\t\t\tpos |= 1 << (3 - uint8(i))\n\t\t\t}","sourceCodeStart":323,"sourceCodeEnd":359,"githubUrl":"https://github.com/XTLS/Xray-core/blob/7d214f8b094f75322fa3990f8aadad1c912f24f5/transport/internet/finalmask/sudoku/table.go#L323-L359","documentation":"Thrown inside customLayout when generating the padding-byte pool for a custom table: it enumerates candidate encodings with at least 5 of 8 bits set and collects distinct results, and the resulting pool is empty. This means the given bit layout cannot produce any valid padding byte, an internal inconsistency between the pattern and the encoder.","triggerScenarios":"A customTable whose x/p bit positions make encodeGroupWithDropX never return a byte with popcount >= 5 across all enumerated groups. This is layout-dependent; most 2/2/4 patterns work, so hitting it indicates an exotic arrangement or a code change in the candidate enumeration.","commonSituations":"Experimenting with unusual permutations of the 8-slot pattern; upgrading the finalmask transport where the padding-generation rules changed while keeping an old custom pattern.","solutions":["Switch to the default layout by clearing customTable (mode prefer_entropy) and retest.","Try a known-good pattern such as \"xxppvvvv\".","If a specific pattern is required, report it upstream so the padding pool rule can be adjusted for that layout."],"exampleFix":"// before\n\"customTable\": \"vvxxppvv\"\n// after\n\"customTable\": \"\"","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"layout, err := resolveLayout(mode, customTable)\nif err != nil {\n\tif strings.Contains(err.Error(), \"empty padding pool\") {\n\t\tlayout, err = resolveLayout(\"prefer_entropy\", \"\") // fall back to default\n\t}\n\tif err != nil {\n\t\treturn err\n\t}\n}","preventionTips":["Prefer the default entropy layout unless you have verified a custom pattern end-to-end.","Add a startup smoke test that builds the table for your exact password+pattern pair."],"tags":["finalmask","sudoku","internal-invariant","config"],"backgroundTag":null,"analyzedSha":"7d214f8b094f75322fa3990f8aadad1c912f24f5","analyzedAt":"2026-08-15T14:26:24.325Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}