base64.b64decode
Accepts str or bytes, returns bytes. By default it quietly skips characters that are not Base64 — but it never forgives missing = padding.
Common call
base64.b64decode(token).decode('utf-8')
Returns
bytes such as b'hello'
Replaces
Hand-written Base64 parsing; codecs.decode(data, "base64")
Watch out
Stripped = padding raises binascii.Error: Incorrect padding
base64.b64decode(ss — The Base64 data. A str must be pure ASCII, otherwise ValueError.type: bytes-like | str · required, altcharsaltchars — The 2 characters used instead of + and /, e.g. "-_". They are translated back to + and / before decoding.type: bytes | str · default: None=None, validatevalidate — False: characters outside the alphabet (spaces, newlines, junk) are discarded. True: any of them — and misplaced padding — raises binascii.Error.type: bool · default: False=False)
→ bytes
Demo
Live evaluation
Decode Base64 text and turn the bytes back into a str with UTF-8.
Try:
Inputs
datastrBase64 text
Code
import base64 base64.b64decode('aGVsbG8gd29ybGQ=').decode()
Result
'hello world'
Lenient mode drops every character outside A–Z a–z 0–9 + / before looking at the padding, so spaces and "!" vanish — and so do - and _, which is why URL-safe text decodes to b'' here. It also stops at the first complete padding, ignoring "aGk=" after it. validate=True turns each of those into an error. A length of 4k + 1 data characters can never be valid, so no amount of padding fixes "YWJjZ".
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| s | bytes-like | str | yes | The Base64 data. A str must be pure ASCII, otherwise ValueError. |
| altchars | bytes | str | no (None) | The 2 characters used instead of + and /, e.g. "-_". They are translated back to + and / before decoding. |
| validate | bool | no (False) | False: characters outside the alphabet (spaces, newlines, junk) are discarded. True: any of them — and misplaced padding — raises binascii.Error. |
Return value
bytes — The decoded data. Call .decode() on it when the original was text.
Common patterns
Decode Base64 to a string
Decode the Base64, then decode the bytes with the text encoding the sender used.
import base64 text = base64.b64decode(encoded).decode('utf-8')
Tolerate missing padding
-len(s) % 4 is exactly the number of = signs that were stripped.
import base64 def b64decode_nopad(s): return base64.b64decode(s + '=' * (-len(s) % 4))
Reject anything that is not clean Base64
validate=True plus except ValueError (binascii.Error is a subclass) covers every bad input.
import base64 try: data = base64.b64decode(user_input, validate=True) except ValueError: data = None
Save decoded data to a file
Write the bytes in binary mode.
import base64 with open('photo.jpg', 'wb') as f: f.write(base64.b64decode(encoded))
Examples
1. str in, bytes out
import base64
base64.b64decode('aGVsbG8=')
Returns
b'hello'2. Back to text
import base64
base64.b64decode('aGVsbG8=').decode()
Returns
'hello'3. Newlines are skipped
import base64
base64.b64decode('aGVs\nbG8=')
Returns
b'hello'4. Missing padding
import base64
base64.b64decode('aGVsbG8')
Returns
binascii.Error: Incorrect padding5. Impossible length
import base64
base64.b64decode('a')
Returns
binascii.Error: Invalid base64-encoded string: number of data characters (1) cannot be 1 more than a multiple of 46. Strict mode
import base64
base64.b64decode('aGk=\n', validate=True)
Returns
binascii.Error: Excess data after padding7. URL-safe input via altchars
import base64
base64.b64decode('-_8=', altchars='-_')
Returns
b'\xfb\xff'8. Non-ASCII str
import base64
base64.b64decode('aGVsbG8=é')
Returns
ValueError: string argument should contain only ASCII charactersPitfalls
1. Stripped padding (JWTs, URLs, copied tokens)
Many producers drop the trailing = signs. b64decode requires them — add them back.
as received
import base64 base64.b64decode('eyJzdWIiOiIxMjMifQ')
binascii.Error: Incorrect padding
pad it
import base64 s = 'eyJzdWIiOiIxMjMifQ' base64.b64decode(s + '=' * (-len(s) % 4))
b'{"sub":"123"}'
2. Silently dropping characters
The default mode discards anything outside the alphabet, so URL-safe or corrupted input "succeeds" with the wrong bytes. validate=True makes it fail loudly.
default
import base64 base64.b64decode('-_-_')
b''
validate=True
import base64 base64.b64decode('-_-_', validate=True)
binascii.Error: Only base64 data is allowed
3. Decoding binary data as text
b64decode returns whatever bytes were encoded. If they are an image or a key, .decode() fails — keep them as bytes.
.decode()
import base64 base64.b64decode('iVBORw0KGgo=').decode()
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x89 in position 0: invalid start byte
keep bytes
import base64 base64.b64decode('iVBORw0KGgo=')[1:4]
b'PNG'
When to use
Use it
- Base64 from JSON, HTTP headers, data: URIs, config files, email
- Standard alphabet (+ and /) input; altchars= for others
Reach for something else
- URL-safe input (- and _) → urlsafe_b64decode, or validate=True to catch it
- Untrusted input you must reject when malformed → pass validate=True
- Multi-line MIME bodies → decodebytes works too; b64decode already skips the newlines
Notes
CPython impl
binascii.a2b_base64(s, strict_mode=validate) in C (the strict_mode parameter exists since Python 3.11)
Padding
Decoding stops at the first complete padding, so anything after "==" is ignored in lenient mode
Exceptions
binascii.Error (a ValueError) for bad data; ValueError for non-ASCII str; TypeError for other types
FAQ
base64.b64decode(s).decode('utf-8'). b64decode accepts the str directly and returns bytes; .decode turns the bytes into text.