apache/hadoop · error · IllegalArgumentException

Wrong length: {hex.length}

Error message

Wrong length: {hex.length}

What it means

Thrown by MD5Hash.setDigest(String) (and the MD5Hash(String) constructor that delegates to it) when the hex string is not exactly MD5_LEN*2 = 32 characters. MD5 renders as 32 hex digits; any other length — 40 (SHA-1), 64 (SHA-256), base64 text, or text with extra characters — is rejected with IllegalArgumentException before any parsing happens.

Source

Thrown at hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/io/MD5Hash.java:285

  /** Returns a string representation of this object. */
  @Override
  public String toString() {
    StringBuilder buf = new StringBuilder(MD5_LEN*2);
    for (int i = 0; i < MD5_LEN; i++) {
      int b = digest[i];
      buf.append(HEX_DIGITS[(b >> 4) & 0xf])
          .append(HEX_DIGITS[b & 0xf]);
    }
    return buf.toString();
  }

  /**
   * Sets the digest value from a hex string.
   * @param hex hex.
   */
  public void setDigest(String hex) {
    if (hex.length() != MD5_LEN*2)
      throw new IllegalArgumentException("Wrong length: " + hex.length());
    byte[] digest = new byte[MD5_LEN];
    for (int i = 0; i < MD5_LEN; i++) {
      int j = i << 1;
      digest[i] = (byte)(charToNibble(hex.charAt(j)) << 4 |
                         charToNibble(hex.charAt(j+1)));
    }
    this.digest = digest;
  }

  private static final int charToNibble(char c) {
    if (c >= '0' && c <= '9') {
      return c - '0';
    } else if (c >= 'a' && c <= 'f') {
      return 0xa + (c - 'a');
    } else if (c >= 'A' && c <= 'F') {
      return 0xA + (c - 'A');
    } else {
      throw new RuntimeException("Not a hex character: " + c);

View on GitHub (pinned to 2add963021)

Solutions

  1. Split and trim checksum-file lines: take the first whitespace-delimited token before constructing MD5Hash.
  2. Confirm the source algorithm is MD5 (32 hex chars); if not, use the matching representation instead of MD5Hash.
  3. Decode base64 to 16 bytes and use MD5Hash(byte[]) if that is the actual encoding.
  4. Validate with a regex before calling setDigest to fail with a clearer message (see validation code).

Example fix

// before: whole line passed, length != 32
String line = new String(Files.readAllBytes(md5File)).trim();
new MD5Hash(line); // throws: line includes the filename

// after: extract just the hash token
String hash = line.split("\\s+")[0].trim();
MD5Hash md5 = new MD5Hash(hash);
Defensive patterns

Strategy: validation

Validate before calling

String h = raw.trim().split("\\s+")[0]; // strip filename from checksum-file lines
if (!h.matches("[0-9a-fA-F]{32}")) {
  throw new IllegalArgumentException("Not an MD5 hex string: '" + raw + "'");
}
new MD5Hash(h);

Type guard

static boolean isMd5Hex(String s) {
  return s != null && s.matches("[0-9a-fA-F]{32}");
}

Prevention

When it happens

Trigger: new MD5Hash(hex) or setDigest(hex) with a checksum string from another algorithm, a base64-encoded digest, or a value with whitespace/quotes/newline attached (e.g. a line read from a checksum file that wasn't trimmed).

Common situations: Parsing .md5 checksum files whose format is '<hash> <filename>' without splitting off the filename; mixing up MD5 and SHA checksums in tooling; copy-pasting digests with trailing newline from a terminal; storing digests base64-encoded and passing them raw.

Related errors


AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22). Data as JSON: /api/errors/072ed70d9832fc02. Report an issue: GitHub.