<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: withuse</title>
    <description>The latest articles on DEV Community by withuse (@_4143d12ca219f32cb635).</description>
    <link>https://dev.to/_4143d12ca219f32cb635</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4165388%2Fa8e1e287-5a80-4993-87fb-d40d6d0e4a1b.png</url>
      <title>DEV Community: withuse</title>
      <link>https://dev.to/_4143d12ca219f32cb635</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/_4143d12ca219f32cb635"/>
    <language>en</language>
    <item>
      <title>atob() does not require padding. It rejects half-padding.</title>
      <dc:creator>withuse</dc:creator>
      <pubDate>Tue, 06 Oct 2026 05:09:28 +0000</pubDate>
      <link>https://dev.to/_4143d12ca219f32cb635/atob-does-not-require-padding-it-rejects-half-padding-11oe</link>
      <guid>https://dev.to/_4143d12ca219f32cb635/atob-does-not-require-padding-it-rejects-half-padding-11oe</guid>
      <description>&lt;p&gt;A common claim about Base64 in the browser is that the input length must be a multiple of 4. It isn't. &lt;code&gt;atob&lt;/code&gt; decodes unpadded input fine. What it rejects is something else.&lt;/p&gt;

&lt;p&gt;Here are all five cases, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"YQ=="     len % 4 = 0   -&amp;gt;  "a"
"YQ"       len % 4 = 2   -&amp;gt;  "a"        &amp;lt;- no padding, still decodes
"YWJjZGU"  len % 4 = 3   -&amp;gt;  "abcde"    &amp;lt;- decodes
"YWJjZ"    len % 4 = 1   -&amp;gt;  throws
"YQ="      len % 4 = 3   -&amp;gt;  throws     &amp;lt;- half-padded
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So the rule has nothing to do with multiples of 4.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Remainder 2 or 3 decodes without padding.&lt;/strong&gt; The leftover bits are enough to reconstruct the bytes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Remainder 1 always fails.&lt;/strong&gt; Six bits cannot encode a byte, so an encoder can never produce that length in the first place.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;If you pad, pad fully.&lt;/strong&gt; &lt;code&gt;"YQ="&lt;/code&gt; is rejected even though its length mod 4 is 3 — the same remainder as &lt;code&gt;"YWJjZGU"&lt;/code&gt;, which passes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The actual contract of &lt;code&gt;atob&lt;/code&gt; is "pad correctly, or do not pad at all", not "length must be a multiple of 4".&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this bites
&lt;/h2&gt;

&lt;p&gt;The rule is not the same across languages. Same input, &lt;code&gt;"YQ"&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;JavaScript   atob("YQ")                             -&amp;gt;  "a"
Python       base64.b64decode("YQ")                 -&amp;gt;  binascii.Error: Incorrect padding
Go           base64.StdEncoding.DecodeString("YQ")  -&amp;gt;  illegal base64 data at input byte 0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;JavaScript is the lenient one and Go is the strictest. A value that round-trips fine in the browser and is then handed to a Python or Go service is a common way to get an error that looks like it came from nowhere — the data was never wrong, the two decoders just disagree about what counts as well-formed.&lt;/p&gt;

&lt;p&gt;If you generate Base64 in the browser and consume it elsewhere, normalize the padding before it crosses the boundary, not after.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verified
&lt;/h2&gt;

&lt;p&gt;Node v23.7.0, Python 3, Go 1.22.0, run on 2026-09-14. The longer write-up — including Go's four encodings, and why picking the wrong one can pass every test and still break in production on one payload — is here: &lt;a href="https://base64.withuse.io/base64-in-go/" rel="noopener noreferrer"&gt;https://base64.withuse.io/base64-in-go/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>go</category>
      <category>python</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
