{"record":{"id":"f0f399c374953390","repo":"XTLS/Xray-core","slug":"decode-key-collision-for-byte-d-and-d","errorCode":null,"errorMessage":"decode key collision for byte %d and %d","messagePattern":"decode key collision for byte (.+?) and (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"transport/internet/finalmask/sudoku/table.go","lineNumber":421,"sourceCode":"\t}\n\tfor b := 0; b < 256; b++ {\n\t\tpatList := patterns[order[b]]\n\t\tif len(patList) == 0 {\n\t\t\treturn nil, fmt.Errorf(\"grid %d has no valid clue set\", order[b])\n\t\t}\n\n\t\tenc := make([][4]byte, 0, len(patList))\n\t\tfor _, groups := range patList {\n\t\t\thints := [4]byte{\n\t\t\t\tlayout.encodeHint(groups[0]),\n\t\t\t\tlayout.encodeHint(groups[1]),\n\t\t\t\tlayout.encodeHint(groups[2]),\n\t\t\t\tlayout.encodeHint(groups[3]),\n\t\t\t}\n\t\t\tsortedHints := sort4(hints)\n\t\t\tkey := packKey(sortedHints)\n\t\t\tif old, exists := t.decode[key]; exists && old != byte(b) {\n\t\t\t\treturn nil, fmt.Errorf(\"decode key collision for byte %d and %d\", old, b)\n\t\t\t}\n\t\t\tt.decode[key] = byte(b)\n\t\t\tenc = append(enc, hints)\n\t\t}\n\n\t\tt.encode[b] = enc\n\t}\n\n\treturn t, nil\n}\n\nfunc getBasePatterns() ([][][4]byte, error) {\n\tbasePatternsOnce.Do(func() {\n\t\tbasePatterns, basePatternsErr = buildBasePatterns()\n\t})\n\treturn basePatterns, basePatternsErr\n}\n","sourceCodeStart":403,"sourceCodeEnd":439,"githubUrl":"https://github.com/XTLS/Xray-core/blob/7d214f8b094f75322fa3990f8aadad1c912f24f5/transport/internet/finalmask/sudoku/table.go#L403-L439","documentation":"Thrown by buildTable when two different byte values produce the same packed sorted-hint decode key, i.e. the byte-to-grid mapping would be ambiguous in the decoder. The table builder detects that pattern sets for two bytes overlap on a key and aborts rather than emit an undecodable table. The shuffle order, and therefore collisions, depend on the password seed and the chosen layout.","triggerScenarios":"Combining a customTable layout with a particular password such that two grids share an identical sorted 4-hint signature. Custom layouts alter which hint bytes are generated, raising collision probability relative to the default layout.","commonSituations":"Using an exotic customTable pattern that was never validated against all 256 grids; reusing a password across transport versions whose hint encoding changed.","solutions":["Change the password; the new shuffle reassigns grids and usually clears the collision.","Remove customTable to use the default entropy layout, which is validated.","If the collision reproduces with the default layout, report the password hash/version upstream."],"exampleFix":"// before\n\"password\": \"secret\", \"customTable\": \"vvxxppvv\"\n// after\n\"password\": \"secret2\", \"customTable\": \"\"","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"for salt := 0; salt < 5; salt++ {\n\tt, err := buildTable(fmt.Sprintf(\"%s-%d\", password, salt), layout)\n\tif err == nil {\n\t\treturn t, nil // use the same salt on both peers\n\t}\n\tif !strings.Contains(err.Error(), \"decode key collision\") {\n\t\treturn nil, err\n\t}\n}","preventionTips":["Both peers must derive the same table; if you salt the password on retry, mirror it on the other side.","Validate custom patterns against all 256 bytes in a test before deploying."],"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"}