Tools Nimbus

Why is my Base64 decode showing garbled text

Tools Nimbus is a free, no-signup developer toolkit that runs entirely in your browser, so your data is never uploaded to a server. Base64 that decodes to garbled text is almost never broken Base64: you decoded the bytes correctly but read them with the wrong character set, or fed URL-safe input to a standard decoder. Paste it into the Tools Nimbus Base64 Decoder, free with no signup, to round-trip UTF-8 cleanly.

Last updated June 2026

Decoding worked. Reading the bytes did not.

It helps to separate two steps that people lump together. Base64 is a way to represent arbitrary bytes as printable ASCII characters. Decoding reverses that and hands you the original bytes back. Those bytes are not necessarily text: they might be a PNG, a protobuf message, or UTF-8-encoded text. The garbling almost always happens in the second step, when something interprets the decoded bytes as text using the wrong character encoding. The Base64 layer did its job perfectly; the bug is downstream.

That distinction is the fastest way to debug. If you decode in the Base64 Decoderand the output is clean, but your code shows mojibake, the problem is your code's text handling, not the string. If even the tool shows garbage, the input itself is malformed and you have a different fix.

Symptom, cause, and fix at a glance

SymptomMost likely causeFix
Accents/emoji become é, Â, �UTF-8 bytes read as Latin-1 or Windows-1252Decode bytes, then read them as UTF-8
Decoder throws or errors outURL-safe - _ sent to a standard decoderReplace - with +, _ with /
"Invalid length" or truncated tailMissing = paddingPad to a multiple of four characters
Random bytes / total nonsenseInput was never Base64, or is double-encodedVerify it is Base64; decode twice if needed
Works partway, then breaksStray whitespace or newlines from copy-pasteStrip all whitespace before decoding

Cause 1: the charset mismatch (the usual culprit)

This is the one that produces é where you expected é, or a black-diamond � replacement character. Your text was UTF-8 before it was Base64-encoded. A UTF-8 é is two bytes (0xC3 0xA9). When the decoder hands those two bytes to something that assumes Latin-1 or Windows-1252, each byte becomes its own character, so one letter turns into two. Emoji, which are four UTF-8 bytes, fan out into four mojibake characters or a box.

The fix is to never treat the decoded bytes as a Latin-1 string. In JavaScript, atob() gives you a binary string of raw bytes; wrap it in a TextDecoder to read it as UTF-8:

// atob alone misreads multi-byte UTF-8
const binary = atob(b64);                 // "é" style mojibake if printed
const bytes  = Uint8Array.from(binary, c => c.charCodeAt(0));
const text   = new TextDecoder("utf-8").decode(bytes);  // correct "é"

In Python the same trap is base64.b64decode(s).decode("latin-1") instead of .decode("utf-8"). The Base64 Decoder does the UTF-8 step for you, so if its output is clean you know the encoding is the only thing your code is getting wrong.

Cause 2: URL-safe input in a standard decoder

Standard Base64 uses + and / as its 63rd and 64th characters. Those characters are awkward in URLs and filenames, so URL-safe Base64 swaps them for - and _ and frequently strips the trailing = padding. JSON Web Tokens and most OAuth flows use this variant. Feed a URL-safe string to a strict standard decoder and it errors; feed it to a lenient one and you get garbage where the - and _ sat.

Convert before decoding: replace every - with + and every _ with /, then re-add = until the length is a multiple of four. If you are pulling apart a token, the JWT Decoder already knows the header and payload are URL-safe Base64 and handles the conversion for you. For the difference between the two alphabets in depth, see Base64 vs Base64URL.

Cause 3: missing or misplaced padding

Base64 encodes three bytes into four characters. When the input is not a multiple of three bytes, the encoder pads the output with one or two = signs so the length stays a multiple of four. Some systems drop that padding to save space. A decoder that expects it then reports an invalid length or silently truncates the last few bytes, which can chop the final character of your text. Re-add = until the string length divides evenly by four and the tail decodes correctly.

A subtler version is an = in the middle of the string. Padding is only ever valid at the very end, so a mid-string = means two separately encoded chunks were concatenated. Split them, or decode the parts independently.

Cause 4: it was never Base64, or it is double-encoded

If the output is complete nonsense rather than mojibake, question the input. A value that looks Base64-ish (letters, digits, the odd + or =) can actually be hex, a URL-encoded string, or a raw token in some other format. Decoding hex as Base64 produces random bytes. Conversely, if a clean decode hands you back something that itself looks like Base64, the value was encoded twice; decode it again. When the bytes are clearly not text at all (a PNG signature, for instance), the data is binary and was never meant to be displayed as a string.

Cause 5: whitespace and copy-paste artifacts

Copying a Base64 blob out of an email, a YAML file, or a chat window often introduces line breaks, tabs, or a non-breaking space. Many decoders tolerate leading and trailing whitespace but choke on whitespace in the middle, decoding everything up to the gap and then failing or producing a truncated result. Strip all whitespace first. If the value arrived inside a JSON payload, clean and inspect that payload in the JSON Formatter so you copy the exact string and nothing around it.

Decode it cleanly in one step

You do not have to guess which cause you are hitting. Open the Base64 Encoder and Decoder, paste your string, and read the output. It decodes to UTF-8 by default, so a correct round trip rules out the charset bug immediately; if the result is still wrong, work down the table above. Because it runs entirely in your browser using the native atob and TextDecoder APIs, the token, config value, or file you paste never leaves your device. If you are decoding the segments of a token, reach for the JWT Decoder instead, and browse the Tools Nimbus guides for more developer fixes.

How to prevent it

  • Standardize on UTF-8 end to end. Encode text as UTF-8 bytes before Base64, and always decode the resulting bytes as UTF-8.
  • Know which alphabet you are using. Tokens and URLs are almost always URL-safe (- _); convert to standard before a standard decoder.
  • Preserve padding, or restore it to a multiple of four characters before decoding.
  • Strip whitespace from copied blobs, and copy the exact value rather than a wrapped or quoted version of it.
  • Remember Base64 is encoding, not encryption. It hides nothing, so decode freely, but never rely on it to protect a secret. See encoding vs encryption vs hashing for why.

Frequently asked questions

Why does my Base64 decode show weird characters like Ã, Â, or �?+

The Base64 decoded fine and you got the right bytes, but those bytes were interpreted with the wrong character set. The classic case is UTF-8 bytes read as Latin-1 or Windows-1252, which turns a single accented letter or emoji into two or three mojibake characters. The fix is to decode the Base64 to raw bytes and then read those bytes as UTF-8, which is what a UTF-8-aware decoder does by default.

Why does my Base64 string fail to decode at all?+

A hard failure (an exception rather than garbled output) is usually invalid input: the string is URL-safe Base64 fed to a standard decoder, it is missing its = padding, it has stray spaces or newlines from a copy-paste, or it simply is not Base64. Strip whitespace, convert - and _ back to + and /, restore padding to a multiple of four characters, and confirm the value is actually Base64 before decoding.

What is the difference between standard and URL-safe Base64 when decoding?+

Standard Base64 uses + and / for its last two alphabet characters, while URL-safe Base64 (used in JWTs and many OAuth tokens) replaces them with - and _ and often drops the = padding. A standard decoder rejects or misreads - and _, so URL-safe input either errors or produces garbage. Either pick a URL-safe decoder or replace - with + and _ with / first, then re-add padding.

Why does my Base64 decode add extra padding characters or null bytes?+

Extra trailing characters usually mean the input was double-encoded (Base64 of Base64) or concatenated from several chunks with padding left in the middle. Padding (=) is only valid at the very end of a complete string; an = in the middle means two separately padded blocks were joined. Decode once, inspect the result, and if it still looks like Base64, decode again.

Is it safe to decode a Base64 token or secret in an online tool?+

It depends entirely on whether the tool uploads your input. Tools Nimbus decodes Base64 entirely in your browser using the native atob and TextDecoder APIs, so the token, payload, or file you paste never leaves your device and is never sent to a server. Avoid any decoder that round-trips your data through a backend for anything sensitive.

Try these browser-based tools mentioned in this guide. Everything runs locally, so your data never leaves your device.