{"record":{"id":"d0ac2d6f755af8ae","repo":"chinabugotech/hutool","slug":"invalid-hash-hash","errorCode":null,"errorMessage":"invalid hash: {hash}","messagePattern":"invalid hash: (.+?)","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"hutool-core/src/main/java/cn/hutool/core/codec/Hashids.java","lineNumber":384,"sourceCode":"\t\t\t\t\t}\n\n\t\t\t\t\t// shuffle the alphabet\n\t\t\t\t\tshuffle(currentAlphabet, decodeSalt);\n\n\t\t\t\t\t// prepend the decoded value\n\t\t\t\t\tfinal long n = translate(block.toString().toCharArray(), currentAlphabet);\n\t\t\t\t\tdecoded = LongStream.concat(decoded, LongStream.of(n));\n\n\t\t\t\t\t// create a new block\n\t\t\t\t\tblock = new StringBuilder(length);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// validate the hash\n\t\tfinal long[] decodedValue = decoded.toArray();\n\t\tif (!Objects.equals(hash, encode(decodedValue))) {\n\t\t\tthrow new IllegalArgumentException(\"invalid hash: \" + hash);\n\t\t}\n\n\t\treturn decodedValue;\n\t}\n\n\tprivate StringBuilder translate(final long n, final char[] alphabet,\n\t\t\t\t\t\t\t\t\tfinal StringBuilder sb, final int start) {\n\t\tlong input = n;\n\t\tdo {\n\t\t\t// prepend the chosen char\n\t\t\tsb.insert(start, alphabet[(int) (input % alphabet.length)]);\n\n\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}","sourceCodeStart":366,"sourceCodeEnd":402,"githubUrl":"https://github.com/chinabugotech/hutool/blob/8870454b2a0c29cc6ffd31dcf5667c8ceb2fc442/hutool-core/src/main/java/cn/hutool/core/codec/Hashids.java#L366-L402","documentation":"Thrown by Hashids.decode() after the round-trip integrity check fails: the decoded numbers are re-encoded and if the result does not match the input hash, the hash is considered corrupt or foreign. This guard ensures decode never silently returns garbage values from a tampered or mismatched hash. The hash was either not produced by this Hashids instance (different salt/alphabet) or was altered after generation.","triggerScenarios":"Calling hashids.decode(\"someHash\") where the hash was generated by a different Hashids instance using a different salt, alphabet, or minLength. Also triggered by manually editing a hash string, truncating it, or passing a hash from a different library implementation. Calling decodeToHex() with the same invalid input also propagates this error.","commonSituations":"Salt mismatch between encode and decode sides (e.g., salt loaded from different config files or environment values across services). Upgrading or changing the Hashids alphabet without re-encoding existing stored hashes. Passing a user-supplied ID from a URL parameter that was malformed or spoofed. Using a different Hashids library version that produces different output.","solutions":["Verify the salt, alphabet, and minLength passed to the Hashids constructor are identical on both the encode and decode sides.","Catch IllegalArgumentException and treat the input as invalid/untrusted — return a 404 or error response instead of crashing.","If migrating salt or alphabet, re-encode all stored hashes before switching, or maintain a legacy Hashids instance for old hashes.","Sanitize user-supplied hash strings before passing to decode — check length and character set against the configured alphabet."],"exampleFix":"// before\nHashids hashids = new Hashids(\"mysalt\".toCharArray(), DEFAULT_ALPHABET, -1);\nlong[] ids = hashids.decode(userInput); // throws on bad input\n\n// after\nHashids hashids = new Hashids(\"mysalt\".toCharArray(), DEFAULT_ALPHABET, -1);\nlong[] ids;\ntry {\n    ids = hashids.decode(userInput);\n} catch (IllegalArgumentException e) {\n    // treat as not found\n    ids = null;\n}","handlingStrategy":"try-catch","validationCode":"// Validate hash charset before decode\nboolean valid = hash != null && hash.chars().allMatch(c -> {\n    char ch = (char) c;\n    return java.util.Arrays.binarySearch(Hashids.DEFAULT_ALPHABET, ch) >= 0 || \"cfhistuCFHISTU\".indexOf(ch) >= 0;\n});","typeGuard":null,"tryCatchPattern":"try {\n    long[] ids = hashids.decode(hash);\n} catch (IllegalArgumentException e) {\n    // hash is invalid or was produced by a different configuration\n    logger.warn(\"Invalid hash decode attempt: {}\", hash);\n    return null; // or throw a domain-specific exception\n}","preventionTips":["Store the salt, alphabet, and minLength configuration alongside hashes to ensure decode compatibility.","Treat all user-supplied hashes as untrusted input.","Never change salt or alphabet without a migration plan for existing hashes.","Add integration tests that encode then decode to verify round-trip integrity."],"tags":["hashids","decode","integrity-check","input-validation","codec"],"backgroundTag":null,"analyzedSha":"8870454b2a0c29cc6ffd31dcf5667c8ceb2fc442","analyzedAt":"2026-08-14T04:01:12.892Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}