The Python 3 Decoder Type Model
Python 3 draws a hard line between bytes (raw binary data) andstr (Unicode text). Base64 is inherently a bytes-in/bytes-out operation, so base64.b64decode() returns bytes. If your source data was text, you must additionally call .decode("utf-8") to get a proper string.
b64decode() is friendly about input: it accepts both str andbytes. When you pass a str, it's internally converted to ASCII bytes first (because Base64 is by definition an ASCII-safe alphabet).
Decoding a Base64 String — Standard Pattern
import base64
# UTF-8 text example
encoded = 'SGVsbG8g5LiW55WMIPCfkYs='
# Step 1: Base64 → bytes
decoded_bytes = base64.b64decode(encoded)
print(decoded_bytes)
# b'Hello \xe4\xb8\x96\xe7\x95\x8c \xf0\x9f\x91\x8b'
# Step 2: bytes → UTF-8 string
decoded_text = decoded_bytes.decode('utf-8')
print(decoded_text)
# 'Hello 世界 👋'
# One-liner
text = base64.b64decode(encoded).decode('utf-8')Decoding a Base64-Encoded File
import base64
# Small to medium files
with open('encoded.txt') as f:
b64_string = f.read().strip()
# Decode and write out
with open('output.png', 'wb') as f:
f.write(base64.b64decode(b64_string))
# Streaming decode for very large files (avoids loading everything into memory)
with open('large.b64', 'rb') as inp, open('large.bin', 'wb') as out:
base64.decode(inp, out) # decodes in blocks
# Verify round-trip
import hashlib
def sha256(path):
h = hashlib.sha256()
with open(path, 'rb') as f:
for chunk in iter(lambda: f.read(65536), b''):
h.update(chunk)
return h.hexdigest()
assert sha256('output.png') == 'expected_hash_here'URL-Safe Base64 (for JWTs and Query Strings)
import base64
def urlsafe_b64decode_padded(s):
"""Decode URL-safe Base64, adding padding if missing."""
# s can be str or bytes
if isinstance(s, str):
s = s.encode('ascii')
# Add padding
padding = -len(s) % 4
if padding:
s += b'=' * padding
return base64.urlsafe_b64decode(s)
# Works with or without padding
raw = urlsafe_b64decode_padded('eyJhbGciOiJIUzI1NiJ9')
print(raw) # b'{"alg":"HS256"}'
# JWT payload decoder
import json
def decode_jwt_payload(jwt):
_, payload_b64, _ = jwt.split('.')
return json.loads(urlsafe_b64decode_padded(payload_b64))
claims = decode_jwt_payload('eyJ...eyJ...abc123')
print(claims['sub'], claims['exp'])Decoding to a Dict / JSON Object
import base64
import json
encoded = 'eyJ1c2VyX2lkIjogNDIsICJyb2xlIjogImFkbWluIn0='
# Base64 → bytes → UTF-8 str → dict
data = json.loads(base64.b64decode(encoded).decode('utf-8'))
print(data)
# {'user_id': 42, 'role': 'admin'}
# Reverse (encode a dict)
encoded2 = base64.b64encode(json.dumps(data).encode('utf-8')).decode('ascii')
assert base64.b64decode(encoded2).decode('utf-8') == json.dumps(data)Decoding an HTTP Basic Auth Header
import base64
def parse_basic_auth(header):
"""Parse an 'Authorization: Basic ...' header into (user, password)."""
if not header.startswith('Basic '):
raise ValueError('Not a Basic auth header')
token = header[6:] # strip 'Basic '
decoded = base64.b64decode(token).decode('utf-8')
if ':' not in decoded:
raise ValueError('Malformed Basic auth token')
user, _, password = decoded.partition(':')
return user, password
user, password = parse_basic_auth('Basic YWRtaW46c2VjcmV0MTIz')
print(user, password) # ('admin', 'secret123')Robust Error Handling
import base64
import binascii
def safe_b64decode(data, urlsafe=False):
"""Decode Base64 with helpful error messages."""
try:
if isinstance(data, str):
data = data.strip().encode('ascii')
else:
data = data.strip()
# Auto-add padding
padding = -len(data) % 4
if padding:
data += b'=' * padding
if urlsafe:
return base64.urlsafe_b64decode(data)
return base64.b64decode(data, validate=True)
except binascii.Error as e:
raise ValueError(f'Invalid Base64: {e}') from e
except UnicodeEncodeError as e:
raise ValueError('Base64 input must be ASCII') from e
# Usage
try:
decoded = safe_b64decode('SGVsbG8h')
print(decoded.decode('utf-8')) # 'Hello!'
except ValueError as e:
print(f'Decode failed: {e}')Common Python Base64 Decode Errors
- binascii.Error: Invalid base64-encoded string — the input contains non-Base64 characters (whitespace, quotes, or leftover data URL prefix). Strip with
.strip()and remove any "data:...;base64," prefix before decoding. - binascii.Error: Incorrect padding— length isn't a multiple of 4. Add padding:
data += b'=' * (-len(data) % 4). - UnicodeDecodeError: 'utf-8' codec can't decode byte— the source wasn't UTF-8 text. Either try a different encoding (Latin-1, UTF-16), or keep the output as bytes if it's binary data.
- Silent wrong output — you called
b64decodeon URL-safe input. Symptoms: valid decode but wrong bytes. Useurlsafe_b64decodewhen the input has-or_. - ValueError: string argument should contain only ASCII— you passed a str with non-ASCII characters (should be impossible for valid Base64). Check that you're passing the encoded string, not the decoded one.
Key Facts
- Module:
- base64 (standard library — no install)
- Standard decode:
- base64.b64decode(data) → bytes
- URL-safe decode:
- base64.urlsafe_b64decode(data)
- Input type:
- str (ASCII) or bytes — both work
- Output type:
- bytes — call .decode("utf-8") for text
- Streaming:
- base64.decode(input_file, output_file) for large files
- Strict mode:
- b64decode(data, validate=True) rejects invalid chars
Related Base64 Tools
- Base64 Encode Python — the encode direction with b64encode()
- Base64 Decode Online — browser tool, no Python needed
- Decode Base64 String — cross-language guide
- Base64 Decode JavaScript — atob() + TextDecoder
- Base64 Image Decoder — data URLs to viewable images
- JWT Debugger — decode full JWT tokens