Skip to content

Why decoded Base64 sometimes looks like garbage

Distinguish valid encoding from UTF-8 text, recover original bytes and troubleshoot a damaged payload using reproducible local examples.

By Sujit Maharjan. Published .

Identify whether the problem is encoding, text interpretation or transport damage before changing the payload.

Separate three different questions

A Base64 value can be valid and still produce unreadable text. Base64 represents bytes; those bytes might be a UTF-8 string, an image, compressed data or something else. Decoding the representation does not identify the correct way to display the result.

Ask three questions separately: Does this string decode as Base64? Do the resulting bytes form text in the expected character encoding? Do those bytes contain the application data you expected? Passing the first check does not answer the other two.

Open Base64 Encoder/Decoder with synthetic examples before investigating a real payload. Avoid copying live credentials into a bug report. The fixture notes describe the downloadable files used below.

Establish a known UTF-8 result

Encode Hello with standard output. The result is SGVsbG8=. Decoding that value returns Hello because those five bytes are valid UTF-8 text.

Now encode the check mark ✓. Its standard output is 4pyT. This visible character occupies three UTF-8 bytes and therefore encodes as four Base64 characters. A character counter and a byte counter answer different questions.

You can download checkmark.txt and import it as a local file. It contains exactly the UTF-8 bytes E2 9C 93, with no newline. Encoding the file should produce the same 4pyT value as encoding the text. A trailing newline in a different source file would produce a different encoding; that would be a different input rather than a broken encoder.

Recover bytes without forcing them into text

Load the URL-safe binary example or paste -_8= in Decode mode. Its standard-alphabet equivalent is +/8=. Both represent the two bytes FB FF, which are not a valid UTF-8 text sequence.

The tool shows a binary summary and offers a download. Copying the sentence “Binary data: 2 bytes” does not recover the original data. Use the binary download, then compare it with the original two-byte fixture.

A local Node.js check is:

const bytes = Buffer.from('+/8=', 'base64');
console.log([...bytes]);
// [251, 255]
console.log(bytes.toString('hex'));
// fbff

Decimal 251 and 255 are hexadecimal FB and FF. That establishes the bytes for this fixture. It does not establish a file format: these two bytes alone are not a complete image or an executable. The tool’s limited MIME sniffing is not a full file validator.

Check transport before repairing the string

If the source uses URL-safe Base64, hyphen and underscore replace plus and slash. This decoder accepts both alphabets and omitted padding. Other applications may require a particular alphabet or explicit padding, so use the destination’s contract when exporting.

If a plus sign traveled through form-style query encoding, check whether it became a space. This tool removes whitespace during decoding; it cannot infer that a missing plus used to be there. Fetch the original value rather than adding characters until the output looks plausible.

ObservationLikely next investigation
A final group has one Base64 characterLook for truncation; padding cannot invent missing bits
Decoding succeeds but UTF-8 failsCheck whether the expected payload is binary or a different text encoding
Text is readable but not the expected documentCheck the source field, compression and application format
A whole JWT fails as one Base64 valueInspect its separate dot-delimited segments with JWT Decoder

A successful decode is not an integrity check. Compare a trusted checksum or expected bytes when the surrounding protocol provides one. Base64 itself provides neither encryption nor authentication.

Compare sizes using bytes

For padded standard Base64, encoded length is 4 × ceil(byte length / 3). Hello uses five bytes and produces eight characters; the three-byte check mark produces four; the two-byte binary fixture also produces four. Short inputs pay proportionally more padding overhead than long ones.

URL-safe output in UToolios omits padding unless a data URI is selected. The two-byte fixture therefore becomes -_8 in that output mode. A data URI also adds a media-type prefix, so its full string length is not the raw Base64 payload length.

Use those distinctions when diagnosing request-size limits. Do not estimate binary file size from the number of visible text characters, and do not assume that removing a prefix or padding is acceptable to every consumer. Local file imports are limited to 200 KB; this tool is intended for focused inspection rather than bulk conversion.

Sources and next steps

RFC 4648 defines the Base64 alphabets and encoding. MDN’s TextDecoder fatal-mode documentation explains why invalid text sequences can be rejected rather than silently replaced.

If the recovered text is supposed to be JSON, use JSON Formatter for syntax inspection while keeping the original bytes. For a token, JWT Decoder separates decoded claims from signature and expiry checks. Neither a readable JSON document nor a decoded token proves trusted application data.

These examples are synthetic and checked against the tools and downloadable files. AI assisted drafting. No particular browser extension, device or production environment is certified by these checks.

Keep investigating

Report a correction with a non-sensitive example
UTooliosUToolios
Theme