alibaba/nacos · error · IllegalArgumentException

illegal hex at index {i}

Error message

illegal hex at index {i}

What it means

NacosAiConfigKeyCodec.fromHex encountered a character at position i that is not a valid hexadecimal digit (0-9, a-f, A-F). The encoder only produces lowercase hex, so any non-hex character indicates corruption or external tampering of the encoded segment.

Source

Thrown at api/src/main/java/com/alibaba/nacos/api/ai/model/NacosAiConfigKeyCodec.java:199

        StringBuilder sb = new StringBuilder(bytes.length * 2);
        for (byte b : bytes) {
            sb.append(Character.forDigit((b >> 4) & 0xF, 16));
            sb.append(Character.forDigit(b & 0xF, 16));
        }
        return sb.toString();
    }
    
    private static byte[] fromHex(String hex) {
        int len = hex.length();
        if ((len & 1) != 0) {
            throw new IllegalArgumentException("illegal hex length: " + len);
        }
        byte[] out = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            int hi = Character.digit(hex.charAt(i), 16);
            int lo = Character.digit(hex.charAt(i + 1), 16);
            if (hi < 0 || lo < 0) {
                throw new IllegalArgumentException("illegal hex at index " + i);
            }
            out[i / 2] = (byte) ((hi << 4) + lo);
        }
        return out;
    }
    
    private static boolean hasReservedEncodedPrefix(String value) {
        return value.regionMatches(true, 0, ENCODED_PREFIX, 0, ENCODED_PREFIX.length());
    }
    
    private static String fitToLength(String candidate, int maxLength, String preservedPrefix) {
        if (candidate == null) {
            return null;
        }
        String prefix = preservedPrefix == null ? "" : preservedPrefix;
        if (candidate.length() <= maxLength && !isHashedPhysicalKey(candidate, prefix)) {
            return candidate;
        }

View on GitHub (pinned to 9b989acdf1)

Solutions

  1. Re-encode the original value with encodeSegment to regenerate clean lowercase hex.
  2. Sanitize the segment: strip non-hex characters or reject if any are found before decoding.
  3. Trace the segment through every transport/storage layer to find where the invalid character was introduced.
  4. Ensure the storage layer preserves exact ASCII bytes (use a binary-safe collation).

Example fix

// before
String bad = "enc.0xGH"; // G, H are not hex
NacosAiConfigKeyCodec.decodeSegment(bad);

// after
if (!bad.substring(4).matches("[0-9a-fA-F]+")) {
    bad = NacosAiConfigKeyCodec.encodeSegment(originalValue);
}
NacosAiConfigKeyCodec.decodeSegment(bad);
Defensive patterns

Strategy: validation

Validate before calling

public static boolean isCleanHex(String hex) {
    if (hex == null || hex.length() % 2 != 0) return false;
    for (int i = 0; i < hex.length(); i++) {
        if (Character.digit(hex.charAt(i), 16) < 0) return false;
    }
    return true;
}

Type guard

public static boolean isDecodableSegment(String s) {
    if (s == null || s.isEmpty()) return true;
    if (!s.startsWith(NacosAiConfigKeyCodec.ENCODED_PREFIX)) return true;
    String hex = s.substring(NacosAiConfigKeyCodec.ENCODED_PREFIX.length());
    return isCleanHex(hex) && !hex.isEmpty();
}

Try / catch

try {
    decoded = NacosAiConfigKeyCodec.decodeSegment(segment);
} catch (IllegalArgumentException e) {
    logger.error("Corrupted encoded segment with non-hex char: {}", segment);
    decoded = NacosAiConfigKeyCodec.encodeSegment(originalValue);
}

Prevention

When it happens

Trigger: An encoded segment contains uppercase letters outside A-F, punctuation, or non-ASCII characters. A URL-decode or character-set conversion mangled the hex string. External system injected unexpected characters into the config key.

Common situations: URL-encoding/decoding applied to a segment that was not designed for URLs. Locale-specific case folding in a database collation. Copy-paste from a rich-text source that inserted invisible characters.

Related errors


AI-assisted analysis of alibaba/nacos@9b989acdf1 (2026-08-14). Data as JSON: /api/errors/d7953ec5eb95f5db. Report an issue: GitHub.