Batu Lab NotesPractical developer guides

Diagnose an odd-length hexadecimal field before unhexlify

By Batu ยท English technical notes

Diagnose an odd-length hexadecimal field before unhexlify

Why does binascii.unhexlify reject an odd number of hexadecimal digits? Each output byte needs two hexadecimal digits, so b'abc' cannot describe a whole byte sequence. Check len(field) % 2 before conversion when callers need a length-specific diagnostic. This example reports odd-length:3 for that input instead of treating it as the same category as malformed hexadecimal text.

The four-case matrix also keeps the boundaries visible. Empty input has zero digits and decodes to b''. b'0abz' has an even count but contains z, so unhexlify is attempted and its binascii.Error becomes non-hexadecimal. The valid control, b'0abc', has four hexadecimal digits and produces b'\x0a\xbc'. The assertions lock down every displayed result.

This pre-check does not prove that an even-length field has only hexadecimal characters; conversion remains necessary for that second condition. Nor does it validate a domain-specific byte length or byte order. Use it when separating an actionable input-length problem from a character-content problem improves an API response or test failure. The standard-library documentation specifies that unhexlify requires an even number of hexadecimal digits and raises binascii.Error otherwise. Python binascii documentation

AI assistance disclosure: This article was drafted with AI assistance and checked against the cited documentation and a synthetic example.

import binascii


def decode_field(field):
    if len(field) % 2:
        return f"odd-length:{len(field)}"
    try:
        return binascii.unhexlify(field)
    except binascii.Error:
        return "non-hexadecimal"


cases = (b"", b"abc", b"0abz", b"0abc")
results = [decode_field(field) for field in cases]
assert results == [b"", "odd-length:3", "non-hexadecimal", b"\x0a\xbc"]

for field, result in zip(cases, results):
    print(f"{field!r} -> {result!r}")
b'' -> b''
b'abc' -> 'odd-length:3'
b'0abz' -> 'non-hexadecimal'
b'0abc' -> b'\n\xbc'