chinabugotech/hutool · error · ValidateException
Base58 checksum is invalid
Error message
Base58 checksum is invalid
What it means
Base58 decoding (with checksum) splits the decoded bytes into payload + 4-byte trailing checksum, recomputes the checksum of the payload, and compares. A mismatch means the input was corrupted, truncated, or is not a valid Base58Check value, and ValidateException is thrown. This is the standard Bitcoin-style Base58Check integrity guard.
Source
Thrown at hutool-core/src/main/java/cn/hutool/core/codec/Base58.java:100
* @return 解码后的bytes
*/
public static byte[] decode(CharSequence encoded) {
return Base58Codec.INSTANCE.decode(encoded);
}
/**
* 验证并去除验证位和版本位
*
* @param data 编码的数据
* @param withVersion 是否包含版本位
* @return 载荷数据
*/
private static byte[] verifyAndRemoveChecksum(byte[] data, boolean withVersion) {
final byte[] payload = Arrays.copyOfRange(data, withVersion ? 1 : 0, data.length - CHECKSUM_SIZE);
final byte[] checksum = Arrays.copyOfRange(data, data.length - CHECKSUM_SIZE, data.length);
final byte[] expectedChecksum = checksum(payload);
if (false == Arrays.equals(checksum, expectedChecksum)) {
throw new ValidateException("Base58 checksum is invalid");
}
return payload;
}
/**
* 数据 + 校验码
*
* @param version 版本,{@code null}表示不添加版本位
* @param payload Base58数据(不含校验码)
* @return Base58数据
*/
private static byte[] addChecksum(Integer version, byte[] payload) {
final byte[] addressBytes;
if (null != version) {
addressBytes = new byte[1 + payload.length + CHECKSUM_SIZE];
addressBytes[0] = (byte) version.intValue();
System.arraycopy(payload, 0, addressBytes, 1, payload.length);
} else {View on GitHub (pinned to 8870454b2a)
Solutions
- Confirm the input was produced by the checked encoder (Base58.encodeChecked); if it is raw Base58 use the non-checked decode path.
- Re-verify the source string character-for-character (single typo invalidates the checksum by design).
- Catch ValidateException and surface a 'corrupt input' error to the user rather than retrying.
Example fix
// before
byte[] payload = Base58.decodeChecked(userInput);
// after
try { byte[] payload = Base58.decodeChecked(userInput); }
catch (ValidateException e) { throw new IllegalArgumentException("address corrupt or mistyped", e); } Defensive patterns
Strategy: try-catch
Validate before calling
// cannot validate checksum without decoding; ensure input came from encodeChecked
if (input == null || input.isEmpty()) throw new IllegalArgumentException("empty base58"); Try / catch
try { return Base58.decodeChecked(s); } catch (ValidateException e) { throw new IllegalArgumentException("corrupt Base58Check input", e); } Prevention
- Use encodeChecked/decodeChecked in pairs.
- Surface checksum failures as user-facing input errors.
When it happens
Trigger: Base58.decode / decodeChecked on a string whose last 4 bytes do not equal the SHA256-double hash of the payload; a typo in a Base58 address; using a raw (unchecked) Base58 string with a checked-decode API.
Common situations: Handling cryptocurrency addresses/keys that the user mistyped; reading Base58 from a transport that dropped/corrupted characters; mixing checked vs unchecked encode/decode.
Related errors
- Invalid char '{}' at [{}]
- Video URI is empty
- File not found!
- Illegal hexadecimal character {} at index {}
- invalid number: {number}
AI-assisted analysis of chinabugotech/hutool@8870454b2a (2026-08-14).
Data as JSON: /api/errors/2312769358ec503c.
Report an issue: GitHub.