{"record":{"id":"5569704904e64eaf","repo":"apache/hadoop","slug":"not-a-hex-character-c","errorCode":null,"errorMessage":"Not a hex character: {c}","messagePattern":"Not a hex character: (.+?)","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/io/MD5Hash.java","lineNumber":303,"sourceCode":"      throw new IllegalArgumentException(\"Wrong length: \" + hex.length());\n    byte[] digest = new byte[MD5_LEN];\n    for (int i = 0; i < MD5_LEN; i++) {\n      int j = i << 1;\n      digest[i] = (byte)(charToNibble(hex.charAt(j)) << 4 |\n                         charToNibble(hex.charAt(j+1)));\n    }\n    this.digest = digest;\n  }\n\n  private static final int charToNibble(char c) {\n    if (c >= '0' && c <= '9') {\n      return c - '0';\n    } else if (c >= 'a' && c <= 'f') {\n      return 0xa + (c - 'a');\n    } else if (c >= 'A' && c <= 'F') {\n      return 0xA + (c - 'A');\n    } else {\n      throw new RuntimeException(\"Not a hex character: \" + c);\n    }\n  }\n\n\n}\n","sourceCodeStart":285,"sourceCodeEnd":309,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/io/MD5Hash.java#L285-L309","documentation":"Thrown by MD5Hash.charToNibble(char) when a character in the supposed hex string is not 0-9, a-f, or A-F. setDigest() walks the string two characters per byte; any stray character (g-z, symbols, whitespace, '0x' prefix) hits this RuntimeException. It means the input was never valid hex, independent of length — the length check in setDigest passed but the content check failed.","triggerScenarios":"setDigest(\"0x\" + hash) or a hash prefixed/suffixed with junk; a checksum line containing the filename because it wasn't split; whitespace or quotes embedded in the string; corrupted checksum files where a byte was replaced by a non-hex character.","commonSituations":"Parsing user-maintained checksum manifests; values read from properties files that still contain quoting; concatenation bugs that glue a path onto the hash; locale/case transformations that insert separators.","solutions":["Pre-validate with a regex (^[0-9a-fA-F]{32}$) and reject with a descriptive error naming the offending input.","Strip non-hex noise before parsing: trim whitespace, remove a leading '0x', split off anything after whitespace.","If the file is genuinely corrupted, regenerate the checksum instead of trying to parse it."],"exampleFix":"// before: prefixed value blows up inside charToNibble\nnew MD5Hash(\"0x\" + hex32);\n\n// after: strict pre-validation with a useful error\nif (!hex32.matches(\"[0-9a-fA-F]{32}\")) {\n  throw new IllegalArgumentException(\"Not an MD5 hex string: '\" + hex32 + \"'\");\n}\nnew MD5Hash(hex32);","handlingStrategy":"validation","validationCode":"if (!hex.matches(\"[0-9a-fA-F]{32}\")) {\n  throw new IllegalArgumentException(\n      \"Invalid MD5 hex '\" + hex + \"' — must be exactly 32 hex chars\");\n}\nmd5.setDigest(hex);","typeGuard":"static boolean isHexNibbleString(String s) {\n  return s != null && s.matches(\"[0-9a-fA-F]*\") && (s.length() % 2) == 0;\n}","tryCatchPattern":null,"preventionTips":["Normalize input before parsing: trim(), strip '0x' prefixes, remove surrounding quotes.","Use a single regex guard ([0-9a-fA-F]{32}) to catch both this error and the length error at once.","Regenerate corrupted checksum manifests rather than special-casing bad characters."],"tags":["md5","hex","validation","hadoop-common"],"backgroundTag":"invalid-hex-string","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}