zloirock/core-js · error · SyntaxError

Malformed padding: only one =

Error message

Malformed padding: only one =

What it means

In a 4-character chunk encoding 2 bytes, the base64 spec requires the second padding '=' to follow the first. If the chunk has exactly 2 characters of data and the remaining input ends (or does not contain a second '=') without providing the second '=', fromBase64 throws this SyntaxError because a 2-byte chunk must be terminated by '=='.

Source

Thrown at packages/core-js/internals/uint8-from-base64.js:124

          throw new SyntaxError('Missing padding');
        }
      }
      read = stringLength;
      break;
    }
    var chr = at(string, index);
    ++index;
    if (chr === '=') {
      if (chunk.length < 2) {
        throw new SyntaxError('Padding is too early');
      }
      index = skipAsciiWhitespace(string, index);
      if (chunk.length === 2) {
        if (index === stringLength) {
          if (lastChunkHandling === 'stop-before-partial') {
            break;
          }
          throw new SyntaxError('Malformed padding: only one =');
        }
        if (at(string, index) === '=') {
          ++index;
          index = skipAsciiWhitespace(string, index);
        }
      }
      if (index < stringLength) {
        throw new SyntaxError('Unexpected character after padding');
      }
      written = writeBytes(bytes, decodeBase64Chunk(chunk, alphabet, lastChunkHandling === 'strict'), written);
      read = stringLength;
      break;
    }
    if (!hasOwn(alphabet, chr)) {
      throw new SyntaxError('Unexpected character');
    }
    var remainingBytes = maxLength - written;
    if (remainingBytes === 1 && chunk.length === 2 || remainingBytes === 2 && chunk.length === 3) {

View on GitHub (pinned to 84e45fba09)

Solutions

  1. Ensure every 2-byte final chunk ends with '==' — append the missing '=' (e.g. 'AB=' → 'AB==').
  2. Verify the string wasn't truncated by a length limit; compare with the expected encoded length ((n+2)/3*4 rounded up).
  3. Pass lastChunkHandling: 'loose' if you intentionally accept non-standard single-padded input only where supported.
  4. Use lastChunkHandling: 'stop-before-partial' if you want to stop at an incomplete final chunk instead of throwing.

Example fix

// before
Uint8Array.fromBase64('QUJD QQ=', { lastChunkHandling: 'strict' }); // Malformed padding: only one =
// after
const fixed = raw.endsWith('=') && !raw.endsWith('==') ? raw + '=' : raw;
Uint8Array.fromBase64(fixed, { lastChunkHandling: 'strict' });
Defensive patterns

Strategy: validation

Validate before calling

function hasCompletePadding(s) {
  const compact = s.replace(/[\t\n\f\r ]/g, '');
  const rem = compact.length % 4;
  if (rem === 0) return true;
  if (rem === 2) return compact.endsWith('==');
  if (rem === 3) return compact.endsWith('=');
  return false; // rem === 1 is always invalid
}

Type guard

function isPaddedBase64(s) {
  if (typeof s !== 'string') return false;
  const c = s.replace(/[\t\n\f\r ]/g, '');
  return c.length % 4 !== 1;
}

Try / catch

try {
  const bytes = Uint8Array.fromBase64(input);
} catch (e) {
  if (e instanceof SyntaxError && e.message.includes('Malformed padding')) {
    throw new TypeError('Base64 requires "==" for 2-byte final chunks');
  }
  throw e;
}

Prevention

When it happens

Trigger: Uint8Array.fromBase64('AB=') or fromBase64('AB= ') (trailing whitespace is skipped, then the string ends) — a chunk with chunk.length === 2 followed by '=' only once, when lastChunkHandling is not 'stop-before-partial'.

Common situations: Base64 strings truncated in transit (e.g. by fixed-width buffers or DB column limits), copy/paste dropping the final character, or strings produced by encoders emitting only one '=' for 2-byte final chunks.

Understand the failure class

Related errors


AI-assisted analysis of zloirock/core-js@84e45fba09 (2026-08-30). Data as JSON: /api/errors/992152b0a3149096. Report an issue: GitHub.