{"record":{"id":"a6eac6907247631f","repo":"chinabugotech/hutool","slug":"invalid-alphabet-for-hash","errorCode":null,"errorMessage":"Invalid alphabet for hash","messagePattern":"Invalid alphabet for hash","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"hutool-core/src/main/java/cn/hutool/core/codec/Hashids.java","lineNumber":415,"sourceCode":"\t\t\t// trim the input\n\t\t\tinput = input / alphabet.length;\n\t\t} while (input > 0);\n\n\t\treturn sb;\n\t}\n\n\tprivate long translate(final char[] hash, final char[] alphabet) {\n\t\tlong number = 0;\n\n\t\tfinal Map<Character, Integer> alphabetMapping = IntStream.range(0, alphabet.length)\n\t\t\t\t.mapToObj(idx -> new Object[]{alphabet[idx], idx})\n\t\t\t\t.collect(Collectors.groupingBy(arr -> (Character) arr[0],\n\t\t\t\t\t\tCollectors.mapping(arr -> (Integer) arr[1],\n\t\t\t\t\t\t\t\tCollectors.reducing(null, (a, b) -> a == null ? b : a))));\n\n\t\tfor (int i = 0; i < hash.length; ++i) {\n\t\t\tnumber += alphabetMapping.computeIfAbsent(hash[i], k -> {\n\t\t\t\tthrow new IllegalArgumentException(\"Invalid alphabet for hash\");\n\t\t\t}) * (long) Math.pow(alphabet.length, hash.length - i - 1);\n\t\t}\n\n\t\treturn number;\n\t}\n\n\tprivate char[] deriveNewAlphabet(final char[] alphabet, final char[] salt, final char lottery) {\n\t\t// create the new salt\n\t\tfinal char[] newSalt = new char[alphabet.length];\n\n\t\t// 1. lottery\n\t\tnewSalt[0] = lottery;\n\t\tint spaceLeft = newSalt.length - 1;\n\t\tint offset = 1;\n\t\t// 2. salt\n\t\tif (salt.length > 0 && spaceLeft > 0) {\n\t\t\tint length = Math.min(salt.length, spaceLeft);\n\t\t\tSystem.arraycopy(salt, 0, newSalt, offset, length);","sourceCodeStart":397,"sourceCodeEnd":433,"githubUrl":"https://github.com/chinabugotech/hutool/blob/8870454b2a0c29cc6ffd31dcf5667c8ceb2fc442/hutool-core/src/main/java/cn/hutool/core/codec/Hashids.java#L397-L433","documentation":"Thrown during Hashids internal decoding when a character in the hash string is not found in the current alphabet mapping. The translate(char[], char[]) method builds a character-to-index map from the alphabet and throws if a hash character has no entry. This indicates the hash contains characters outside the configured alphabet character set.","triggerScenarios":"Decoding a hash string that contains characters not present in the Hashids instance's filtered alphabet. This can happen when a hash from a different Hashids configuration (with a different alphabet) is decoded, or when the hash string has been corrupted with foreign characters. The error originates inside decode() at the translate call on line 372 and surfaces before the round-trip validation on line 383.","commonSituations":"Mixing hashes from different Hashids instances with custom alphabets. Passing arbitrary strings (URL slugs, UUIDs) to decode() that were never Hashids-encoded. Character encoding issues where the hash string is mangled in transit (e.g., URL-decoded incorrectly).","solutions":["Ensure the hash being decoded was produced by a Hashids instance with the same alphabet configuration.","Validate that the input string contains only characters from the expected alphabet and guard characters before calling decode.","Catch IllegalArgumentException around the decode call and handle invalid input gracefully.","Check for URL-encoding or HTML-encoding issues that may have altered the hash string before it reached decode()."],"exampleFix":"// before\nlong[] ids = hashids.decode(userInput); // throws if char not in alphabet\n\n// after\nSet<Character> valid = new HashSet<>();\nfor (char c : \"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890\") valid.add(c);\nboolean allValid = userInput.chars().allMatch(c -> valid.contains((char)c));\nlong[] ids = allValid ? hashids.decode(userInput) : null;","handlingStrategy":"try-catch","validationCode":"// Check all hash chars are in the alphabet before decode\nSet<Character> alphabetChars = new HashSet<>();\nfor (char c : hashidsAlphabet) alphabetChars.add(c);\nboolean allValid = hash.chars().allMatch(c -> alphabetChars.contains((char) c));","typeGuard":null,"tryCatchPattern":"try {\n    long[] ids = hashids.decode(hash);\n} catch (IllegalArgumentException e) {\n    // hash contains chars not in alphabet, or round-trip failed\n    return null;\n}","preventionTips":["Always use the same Hashids instance (or identical configuration) for encode and decode.","Validate user input character sets before passing to decode.","Log invalid decode attempts to detect probing or data corruption."],"tags":["hashids","decode","alphabet","input-validation","codec"],"backgroundTag":null,"analyzedSha":"8870454b2a0c29cc6ffd31dcf5667c8ceb2fc442","analyzedAt":"2026-08-14T04:01:12.892Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}