zloirock/core-js · error · SyntaxError

Malformed padding: exactly one additional character

Error message

Malformed padding: exactly one additional character

What it means

When decoding reaches the end of the input with a leftover partial chunk, 'loose' lastChunkHandling accepts a 2- or 3-character final chunk (without padding) but rejects a single leftover character, because one base64 char carries only 6 bits — not enough to encode any byte. This SyntaxError reports that exact case.

Source

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

  if (into) notDetached(into.buffer);

  var stringLength = string.length;
  var bytes = into || $Array(floor(stringLength * 3 / 4));
  var written = 0;
  var read = 0;
  var chunk = '';
  var index = 0;

  if (maxLength) while (true) {
    index = skipAsciiWhitespace(string, index);
    if (index === stringLength) {
      if (chunk.length > 0) {
        if (lastChunkHandling === 'stop-before-partial') {
          break;
        }
        if (lastChunkHandling === 'loose') {
          if (chunk.length === 1) {
            throw new SyntaxError('Malformed padding: exactly one additional character');
          }
          written = writeBytes(bytes, decodeBase64Chunk(chunk, alphabet, false), written);
        } else {
          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) {

View on GitHub (pinned to 84e45fba09)

Solutions

  1. Fix the source data — a single trailing base64 char is never valid; the string is truncated or corrupt.
  2. Use lastChunkHandling: 'stop-before-partial' to decode only up to the last complete chunk.
  3. Add missing padding: a 1-char tail cannot be padded to validity, so repair/re-request the data.
  4. Validate `string.length % 4 !== 1` before decoding.

Example fix

// before
Uint8Array.fromBase64('QQBj'); // chunks 'QQBj' ok — but 'QQBjx' leaves chunk 'x' -> SyntaxError
// after
const s = b64.replace(/\s/g, '');
if (s.length % 4 === 1) throw new Error('truncated base64');
Uint8Array.fromBase64(s);
Defensive patterns

Strategy: validation

Validate before calling

const s = b64.replace(/\s/g, '');
if (s.length % 4 === 1) {
  throw new Error('base64 input truncated: single trailing character cannot encode any byte');
}

Type guard

function isDecodableBase64Length(s) { return s.replace(/\s/g, '').length % 4 !== 1; }

Try / catch

try {
  bytes = Uint8Array.fromBase64(b64);
} catch (e) {
  if (e instanceof SyntaxError && /Malformed padding/.test(e.message)) {
    bytes = Uint8Array.fromBase64(b64, { lastChunkHandling: 'stop-before-partial' });
  } else throw e;
}

Prevention

When it happens

Trigger: `Uint8Array.fromBase64('QQ A'.replace(/\s/g,''))`-style input whose final group is exactly 1 character, e.g. 'QUIx' (4+... wait) — concretely a string like 'QQB'+'j' where the last chunk after splitting into 4s is 'j'. Also whitespace-split strings that lost characters.

Common situations: Base64 strings truncated by one character during copy/paste or storage trimming, custom encoders emitting a lone trailing char, or regex/split processing that dropped '=' padding leaving one char.

Understand the failure class

Related errors


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