chinabugotech/hutool · error · UtilException

Illegal hexadecimal character {} at index {}

Error message

Illegal hexadecimal character {} at index {}

What it means

Base16Codec.toDigit converts a single hex char to its integer value via Character.digit(ch, 16); when the char is not a valid hex digit (0-9, a-f, A-F) the result is -1 and a UtilException (a RuntimeException) is thrown naming the offending char and its index. This occurs during hex decoding.

Source

Thrown at hutool-core/src/main/java/cn/hutool/core/codec/Base16Codec.java:114

	public void appendHex(StringBuilder builder, byte b) {
		int high = (b & 0xf0) >>> 4;//高位
		int low = b & 0x0f;//低位
		builder.append(alphabets[high]);
		builder.append(alphabets[low]);
	}

	/**
	 * 将十六进制字符转换成一个整数
	 *
	 * @param ch    十六进制char
	 * @param index 十六进制字符在字符数组中的位置
	 * @return 一个整数
	 * @throws UtilException 当ch不是一个合法的十六进制字符时,抛出运行时异常
	 */
	private static int toDigit(char ch, int index) {
		int digit = Character.digit(ch, 16);
		if (digit < 0) {
			throw new UtilException("Illegal hexadecimal character {} at index {}", ch, index);
		}
		return digit;
	}
}

View on GitHub (pinned to 8870454b2a)

Solutions

  1. Sanitise input: strip 0x prefixes, whitespace, colons and uppercase/lowercase to a-f before decoding.
  2. Validate with a regex (^[0-9a-fA-F]+$) and even length before calling decode.
  3. Use HexUtil.decodeHexStr/decodeHex with a try-catch to report the bad input to the user.

Example fix

// before
byte[] b = HexUtil.decodeHex("0x1F:2A");
// after
String clean = input.replaceAll("0x|:|\\s", "");
if (!clean.matches("^[0-9a-fA-F]+$") || clean.length()%2!=0) throw new IllegalArgumentException("bad hex");
byte[] b = HexUtil.decodeHex(clean);
Defensive patterns

Strategy: validation

Validate before calling

String clean = input.replaceAll("0x|:|\\s", "");
if (!clean.matches("^[0-9a-fA-F]+$") || clean.length()%2!=0) throw new IllegalArgumentException("invalid hex: " + input);

Type guard

static boolean isHex(String s) { return s != null && s.matches("^[0-9a-fA-F]+$") && s.length()%2==0; }

Try / catch

try { return HexUtil.decodeHex(s); } catch (UtilException e) { throw new IllegalArgumentException("bad hex input", e); }

Prevention

When it happens

Trigger: Decoding a string containing non-hex characters (g-z, punctuation, whitespace) via HexUtil.decodeHex or Base16.decode. An odd-length input or characters outside [0-9a-fA-F].

Common situations: Parsing user input or file content assumed to be hex; concatenating hex strings with separators (0x prefix, colons) not stripped; encoding/decoding mismatch (treating base64 as hex).

Related errors


AI-assisted analysis of chinabugotech/hutool@8870454b2a (2026-08-14). Data as JSON: /api/errors/f5413dcf0383f355. Report an issue: GitHub.