Encoding

Base64 Decode "Invalid Character" Error: How to Fix

The Base64 "invalid character" error means the input string contains a character that isn't part of the Base64 alphabet. The most common causes are URL-safe characters, whitespace, missing padding, and input that isn't Base64 at all.

Error → Likely Cause
atob: invalid character → URL-safe Base64 (-,_) or whitespace
incorrect padding → Missing or extra = at end
Invalid base64-encoded string → Python/Node version of the same errors
Non-base64 digit → Input is hex, plaintext, or a different encoding

Error 1: URL-safe Base64 Characters (- and _)

Standard Base64 uses + and /. URL-safe Base64 (Base64url) replaces them with - and _. JWT tokens always use Base64url. Standard decoders reject - and _ as invalid.

Will fail with atob()
eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.SflKxw-RJSMeKKF2QT4fw
← contains - and _ (JWT)
Fix: convert before decoding
// JavaScript
function decodeBase64url(str) {
str = str
.replace(/-/g, '+')
.replace(/_/g, '/');
const pad = str.length % 4;
if (pad) str += '='.repeat(4 - pad);
return atob(str);
}

Error 2: Whitespace and Line Breaks

MIME Base64 (used in email) inserts a line break every 76 characters. If you copy Base64 from an email or PEM file, the line breaks cause "invalid character" errors.

// Strip whitespace before decoding
const clean = base64String
.replace(/\s+/g, ''); // removes spaces, newlines, tabs
const decoded = atob(clean);
# Python
import base64
clean = base64_str.replace(r'\s', '')
# Or use validate=False to ignore whitespace:
decoded = base64.b64decode(base64_str, validate=False)

Error 3: Incorrect Padding

Base64 output length must be a multiple of 4. If the encoded string is missing= padding, some decoders fail.

// Add missing padding
function addPadding(str) {
const pad = str.length % 4;
return pad ? str + '='.repeat(4 - pad) : str;
}

Note: URL-safe Base64 (JWTs) deliberately omits padding. Add it back before using standard atob().

Error 4: The String Is Not Base64

Sometimes the input isn't Base64 at all — it might be hex, a UUID, a raw password, or already decoded text.

Looks likeIt's actuallyWhat to do
2cf24dba5fb0a30e...Hex (SHA-256 hash)Use hex decode: Buffer.from(str, "hex")
550e8400-e29b-41d4...UUIDNo decoding needed — it's already text
abc123!@#$Plain text or passwordDo not decode — it's not encoded
%2B%2F%3D...URL-encoded Base64URL-decode first: decodeURIComponent(str)
SGVsbG8=Valid standard Base64Decode with atob() or equivalent

Error 5: "atob is not defined" (Node.js)

atob() and btoa() are browser APIs. They were added to Node.js in v16 (global) and are stable in v18+. For older Node.js or guaranteed compatibility, use Buffer:

// Node.js — works in all versions
const decoded = Buffer.from(base64str, 'base64').toString('utf8');
const encoded = Buffer.from(text).toString('base64');
// URL-safe Base64 (Node.js)
const decoded = Buffer.from(base64url, 'base64url').toString('utf8');

Debug Checklist

Does the string contain - or _ ? → URL-safe Base64, convert to + and /
Does the string have spaces, newlines, or tabs? → Strip whitespace first
Is the string length not a multiple of 4? → Add = padding
Does it look like hex (only 0-9, a-f)? → Use hex decode instead
Is the error in Node.js? → Use Buffer.from(str, "base64") not atob()
Did the string come from a URL? → URL-decode it first with decodeURIComponent()
Is there = in the middle of the string? → Truncated or corrupted input

Frequently Asked Questions

Why does my JWT fail to decode with atob()?

JWTs use Base64url (URL-safe Base64) which replaces + with - and / with _ and omits = padding. Standard atob() rejects - and _ as invalid characters. To decode a JWT payload: const parts = token.split("."); const payload = JSON.parse(atob(parts[1].replace(/-/g, "+").replace(/_/g, "/"))). Or use a JWT library which handles this automatically.

What is the valid Base64 character set?

Standard Base64 (RFC 4648): A-Z (26), a-z (26), 0-9 (10), + and / (2) = 64 characters, plus = for padding. URL-safe Base64: same but - replaces + and _ replaces /. Characters outside this set (spaces, newlines, !, @, #, etc.) are invalid and will cause decode errors.

How do I check if a string is valid Base64?

Test with a regex: /^[A-Za-z0-9+/]*={0,2}$/.test(str) for standard Base64. Or simply attempt to decode and catch the error. Note that some strings pass the regex but decode to unexpected data if the padding is wrong.

Can Base64 decode the wrong data silently?

Yes. If padding is wrong or the string has extra characters, some lenient decoders may silently produce garbage output instead of throwing an error. Python's base64.b64decode() with validate=False will skip invalid characters. Always use validate=True (or the equivalent strict mode) in security-sensitive contexts.

Key Takeaways

  • "Invalid character" usually means URL-safe Base64 (-,_) or whitespace in the string.
  • Always strip whitespace before decoding MIME Base64 from emails or PEM files.
  • JWTs use Base64url — replace - with + and _ with / before using atob().
  • In Node.js, use Buffer.from(str, 'base64') instead of atob() for full compatibility.
  • If "incorrect padding": add = characters until length is a multiple of 4.

Related Resources