One equals, two equals, sometimes none. The trailing = signs in Base64 follow a simple rule about input length. Here's the rule, the edge cases, and how to fix "invalid padding" errors.
Look at these three Base64 strings:
TWFu (no padding)
TWE= (one equals)
TQ== (two equals)
They're Man, Ma, and M respectively. The number of = signs at the end tells you something about the length of the original. What exactly?
Base64 works on groups of 3 input bytes, producing groups of 4 output characters. When the input length is divisible by 3, no padding is needed. When the input has 1 leftover byte at the end, that byte produces 2 output characters plus == as filler. When the input has 2 leftover bytes, they produce 3 output characters plus a single =.
| Input bytes (length mod 3) | Output Base64 characters | Padding |
|---|---|---|
| 0 (length divisible by 3) | length × 4/3 | none |
| 1 (one byte left over) | 2 chars from the byte + == | == |
| 2 (two bytes left over) | 3 chars from the bytes + = | = |
So that the encoded length is always a multiple of 4. This makes parsing easy: read 4 characters, decode 3 bytes, repeat. Without padding, parsers would need special logic for the last group.
The padding character is = specifically because it doesn't appear anywhere else in the Base64 alphabet — when a decoder sees it, the meaning is unambiguous: "this position is filler, ignore it."
URL-safe contexts often drop the padding. JWTs do. Many OAuth flows do. The reason: = has special meaning in URLs (it separates query parameters), and the padding is redundant anyway — the decoder can recompute it from the length.
If you've ever seen a JWT like eyJhbGciOi...XyZ with no trailing equals, that's why.
Permissive decoders compute how much padding the input should have, add it, and decode normally. The rule:
missing = (4 - len(input) % 4) % 4
padded = input + ("=" * missing)
If the input length mod 4 is 0, no padding needed. If it's 2, add ==. If it's 3, add =. If it's 1, the input is malformed — that's not a valid Base64 length.
Our decoder handles missing padding silently. Paste a JWT segment without padding, paste a string with extra padding — it just works either way.
If a stricter decoder complains, the fix is usually adding equals signs. From the Python example above:
def fix_padding(s):
return s + "=" * (-len(s) % 4)
This works for any Base64 string — standard or URL-safe — that has had its padding stripped.
= at the end → 2 trailing characters carry 1 byte.== at the end → 2 trailing characters carry 1 byte. Wait, isn't that the same thing? No — with one =, you have 3 meaningful characters + 1 padding. With two ==, you have 2 meaningful characters + 2 padding. Different number of input bytes, different padding count.=== → malformed. A valid Base64 string never has more than 2 padding characters.Paste any of these into the decoder, with or without the padding — same result:
SGVsbG8sIHdvcmxkIQ==
SGVsbG8sIHdvcmxkIQ
SGVsbG8sIHdvcmxkIQ====
Published May 2026 · Last reviewed May 2026. Spot an error? Email contactus@base64decode.tools.