base64.b32decode() vs b32hexdecode(): Wrong Variant Decodes Silently (tested)
Python's base64 module has two different Base32 alphabets: the standard one (b32encode/b32decode) and the RFC 4648 'Extended Hex' one (b32hexencode/b32hexdecode). We measured what happens if you encode with one and accidentally decode with the other -- for some inputs it raises an error, but for others it silently returns completely wrong bytes with no error at all.
1. The two alphabets overlap on letters A-V
import base64
print(base64.b32encode(b"hello world"))
print(base64.b32hexencode(b"hello world"))
b'NBSWY3DPEB3W64TMMQ======'
b'D1IMOR3F41RMUSJCCG======'
Measured: the standard alphabet is A-Z2-7; the Extended Hex alphabet is 0-9A-V. They assign different numeric values to the same letters -- in standard Base32, A is digit 0 and letters run through Z=25 before digits 2-7 cover 26-31; in Extended Hex, 0-9 cover 0-9 and letters A-V cover 10-31. A letter like A means a different value in each scheme.
2. Mismatched input that uses only A-V decodes silently -- to the wrong bytes
import base64
data = b"\x01\x01\x01\x01\x01"
encoded = base64.b32encode(data)
print(encoded)
print(base64.b32decode(encoded)) # correct function
print(base64.b32hexdecode(encoded)) # wrong function
b'AEAQCAIB'
b'\x01\x01\x01\x01\x01'
b'S\x95\xa6*K'
Measured: this particular standard-Base32 output happens to use only the letters A-V, which are all valid digits in the Extended Hex alphabet too. So b32hexdecode() doesn't raise -- it runs to completion and returns 5 bytes that look like a normal, valid result, but are nothing like the original data. There is no exception, no warning, and no length mismatch to tip you off.
3. Input containing a digit or W-Z does raise -- but you can't rely on that
import base64
encoded = base64.b32encode(b"hello world")
print(encoded)
try:
base64.b32hexdecode(encoded)
except Exception as e:
print(type(e).__name__, e)
b'NBSWY3DPEB3W64TMMQ======'
Error Non-base32 digit found
Measured: this encoded value contains digits (3, 6, 4) and letters outside A-V (W, Y), neither of which are valid in the Extended Hex alphabet, so this particular mismatch correctly raises binascii.Error. But whether a given mismatch raises or silently succeeds depends entirely on which characters the ciphertext-of-the-moment happens to contain -- there's no way to know in advance, and nothing in the API protects you. If your code might receive either variant, record which one was used alongside the encoded value, or always normalize to one variant before it leaves your system.
Frequently asked questions
What's the difference between base64.b32decode() and b32hexdecode()?
They decode two different RFC 4648 Base32 alphabets: b32decode() expects A-Z2-7 (standard), b32hexdecode() expects 0-9A-V (Extended Hex). We measured that the two assign different numeric values to the same letters.
Does Python raise an error if I decode Base32 with the wrong variant?
Not always -- we measured this directly: if the encoded text happens to use only letters A-V, which are valid digits in both alphabets, the wrong decoder runs without error and returns completely different, wrong bytes.
Can base32 decoding fail silently in Python?
Yes, for this specific mismatch -- we confirmed that decoding standard-alphabet Base32 output with b32hexdecode() (or vice versa) can return wrong bytes with no exception, when the ciphertext doesn't contain any character unique to the other alphabet.
How do I avoid mixing up Base32 variants?
Always pair b32encode() with b32decode(), and b32hexencode() with b32hexdecode() -- never assume the decoder will catch a mismatch, since we measured that it only raises for some inputs, not all.
Why did my Base32 decode return garbage instead of an error?
Likely a standard/Extended-Hex alphabet mismatch. We measured that this silently succeeds whenever the encoded text only contains characters valid in both alphabets (digits and letters A-V), producing wrong output with no error to flag it.
Written with AI assistance. Measured on 2026-10-04 with Python 3.13.5's built-in base64 module: encoded several short byte strings with base32encode() (RFC 4648 standard alphabet), then decoded the result with base32hexdecode() (RFC 4648 'Extended Hex' alphabet) instead of the matching base32decode(), and compared outputs. PlainHeaders is our extension; Python's base64 module is built in.