{"record":{"id":"8808d15149bc890e","repo":"XTLS/Xray-core","slug":"grid-d-has-no-valid-clue-set","errorCode":null,"errorMessage":"grid %d has no valid clue set","messagePattern":"grid (.+?) has no valid clue set","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"transport/internet/finalmask/sudoku/table.go","lineNumber":407,"sourceCode":"\tfor i := range order {\n\t\torder[i] = i\n\t}\n\n\thash := sha256.Sum256([]byte(password))\n\tseed := int64(binary.BigEndian.Uint64(hash[:8]))\n\trng := rand.New(rand.NewSource(seed))\n\trng.Shuffle(len(order), func(i, j int) {\n\t\torder[i], order[j] = order[j], order[i]\n\t})\n\n\tt := &table{\n\t\tdecode: make(map[uint32]byte, 1<<16),\n\t\tlayout: layout,\n\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}","sourceCodeStart":389,"sourceCodeEnd":425,"githubUrl":"https://github.com/XTLS/Xray-core/blob/7d214f8b094f75322fa3990f8aadad1c912f24f5/transport/internet/finalmask/sudoku/table.go#L389-L425","documentation":"Thrown by buildTable when the password-seeded shuffle assigns byte b a grid index whose pattern list is empty (no valid clue set). Each of the 256 shuffled grids must carry at least one clue pattern; an empty one breaks encoding for that byte value. Internal invariant, but the assignment depends on the password seed.","triggerScenarios":"A grid that survived the >=256 count check but has an empty per-grid pattern list for the specific password-derived shuffle order. Only reachable if upstream pattern generation produced a partially-filled entry.","commonSituations":"Custom or patched builds with modified pattern generation; not observed with stock binaries. Changing the password alters the shuffle and can mask or expose the condition.","solutions":["Change the password field; the reseeded shuffle may avoid the empty grid.","Verify you are on a released, consistent build of the transport.","Report upstream with the password (if non-sensitive) and version if it persists."],"exampleFix":"// before\n\"password\": \"alpha\"\n// after\n\"password\": \"alpha2\"","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"var t *table\nfor attempt := 0; attempt < 3; attempt++ {\n\tvar err error\n\tt, err = buildTable(passwordWithAttemptSalt(attempt), layout)\n\tif err == nil || !strings.Contains(err.Error(), \"no valid clue set\") {\n\t\tbreak\n\t}\n}","preventionTips":["Since grid assignment is password-seeded, changing the password changes the outcome; keep configs reproducible.","Report persistent occurrences upstream rather than working around them blindly."],"tags":["finalmask","sudoku","internal-invariant","startup"],"backgroundTag":null,"analyzedSha":"7d214f8b094f75322fa3990f8aadad1c912f24f5","analyzedAt":"2026-08-15T14:26:24.325Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}