Загрузить файл
  1. base64hub
  2. Статьи о Base64
  3. Ошибки Base64
Решение проблем

Ошибки декодирования Base64 и как их исправить

Почти все сбои Base64 сводятся к пяти причинам: не тот алфавит, нет дополнения, лишние символы, не та кодировка текста или двойное кодирование. Найдите своё сообщение об ошибке ниже и переходите к решению.

Сообщения об ошибках коротко

СообщениеГде встречаетсяНаиболее вероятная причина
binascii.Error: Incorrect paddingPython base64.b64decodeНет = в конце, часто из-за Base64URL или обрезанной строки
binascii.Error: Invalid base64-encoded string: number of data characters (5) cannot be 1 more than a multiple of 4PythonОбрезанная строка или молча отброшенные -/_
binascii.Error: Only base64 data is allowedPython с validate=TrueПеревод строки, пробел, - или _ во входных данных
InvalidCharacterError: Failed to execute 'atob' on 'Window': The string to be decoded is not correctly encoded.Chrome, EdgeСимволы Base64URL, мусорные символы, неверная длина
InvalidCharacterError: String contains an invalid characterFirefoxТо же самое
InvalidCharacterError: Invalid characterNode.js atobТо же самое
IllegalArgumentException («Illegal base64 character …»)Java java.util.Base64Декодер не под тот алфавит или переносы строк
FormatException.NET Convert.FromBase64StringСимволы Base64URL или нет дополнения
base64: invalid inputGNU coreutils base64 -dСимволы вне алфавита

Исправляем ошибки декодеров

«Incorrect padding» в Python

Длина вывода Base64 всегда кратна 4, а конец дополняется знаками =. Декодер Python дополнения требует:

>>> import base64
>>> base64.b64decode("SGVsbG8")
Traceback (most recent call last):
  ...
binascii.Error: Incorrect padding
>>> base64.b64decode("SGVsbG8=")
b'Hello'

Отсутствие дополнения обычно означает, что строка в Base64URL (JWT, URL-токены и многие API отбрасывают =) или что её кто-то обрезал. Верните дополнение:

s = "SGVsbG8"
s += "=" * (-len(s) % 4)

Если длина на единицу больше кратной 4, дополнение не поможет. Тогда Python сообщает number of data characters (5) cannot be 1 more than a multiple of 4. Один оставшийся символ содержит только 6 бит, так что часть данных потеряна. На это сообщение можно нарваться и менее очевидным путём: без validate=True Python выбрасывает символы вне алфавита, в том числе - и _. base64.b64decode("SGk_Pg==") отбрасывает _, и остаётся 5 символов данных. Для Base64URL используйте base64.urlsafe_b64decode.

«Invalid character» и сбои atob

Браузеры реализуют atob по одному алгоритму, но формулируют ошибку по-разному. В Chrome это «The string to be decoded is not correctly encoded», в Firefox «String contains an invalid character», в Node.js «Invalid character». Все три бросают InvalidCharacterError на таких входных данных:

  • Символы Base64URL. atob("SGk_Pg") падает из-за _. Сначала замените - на +, а _ на /.
  • Длина 4n+1 после удаления пробелов, например atob("A").
  • Посторонние символы: кавычки, скопированные из JSON, префикс data:, %2F от URL-кодирования.

Кое-что atob всё же прощает. Он пропускает пробелы и переводы строк и принимает строку без дополнения, если длина позволяет, так что atob("SGVsbG8") возвращает "Hello". Зеркальная ошибка, когда btoa падает с «characters outside of the Latin1 range», связана с текстом в Unicode и разобрана в статье Uint8Array.toBase64.

Терпимый декодер, который понимает оба алфавита, пробелы и отсутствие дополнения:

function decodeLoose(s) {
  s = s.replace(/\s+/g, "").replace(/-/g, "+").replace(/_/g, "/");
  s += "=".repeat((4 - (s.length % 4)) % 4);
  return Uint8Array.from(atob(s), (c) => c.charCodeAt(0));
}

new TextDecoder().decode(decodeLoose("SGk_Pg")); // "Hi?>"

То же на Python:

import base64

def b64decode_any(s: str) -> bytes:
    s = "".join(s.split())
    s = s.replace("-", "+").replace("_", "/")
    s += "=" * (-len(s) % 4)
    return base64.b64decode(s, validate=True)

Инструмент починка Base64 выполняет ту же очистку и сообщает, что именно изменил.

«Illegal base64 character» в Java и FormatException в .NET

В java.util.Base64 три декодера, и каждый строго держится своего алфавита. Сообщение называет проблемный символ в hex: 5f (_), 2d (-), 2f (/), 20 (пробел), a (перевод строки).

Во входных данных естьИспользуйте
+ и /Base64.getDecoder()
- и _Base64.getUrlDecoder()
Переносы строк (MIME, тела PEM)Base64.getMimeDecoder()

Базовый декодер отвергает переносы строк и пробелы. Отсутствие дополнения он при этом допускает, так что SGVsbG8 декодируется без возражений.

Convert.FromBase64String в .NET бросает FormatException на символах Base64URL и при отсутствии дополнения. Пробелы и переносы строк он пропускает. Перед вызовом исправьте алфавит и дополнение, как показано выше. Полные примеры есть на страницах Base64 в Java и Base64 в C#.

Текст получается искажённым

Декодирование прошло успешно, но текст выглядит неправильно. Base64 хранит байты, а байты были получены из текста в какой-то кодировке. Если прочитать их в другой, получатся кракозябры.

Вы видитеИсходный текстЧто произошло
CaféCaféБайты UTF-8 прочитаны как Latin-1 или Windows-1252
Caf�CaféБайты Windows-1252 прочитаны как UTF-8
H e l l o или H\0e\0l\0l\0o\0HelloБайты UTF-16LE прочитаны как UTF-8

Первая строка таблицы описывает классическую ловушку atob. atob("Q2Fmw6k=") возвращает "Café", потому что atob сопоставляет каждому байту один символ. Вместо этого декодируйте байты как UTF-8:

const bytes = Uint8Array.from(atob("Q2Fmw6k="), (c) => c.charCodeAt(0));
new TextDecoder().decode(bytes); // "Café"

UTF-16LE часто встречается у инструментов Windows: его выдают -EncodedCommand в PowerShell и многие API .NET. В инструменте Base64 в текст можно переключать кодировку, пока текст не станет читаемым, а Base64 в UTF-16 справляется со случаем «широких» символов.

Результат похож на двоичные данные

Если декодированный результат полон �, управляющих символов или фрагментов PNG, PK и %PDF, внутри лежит файл. Посмотрите на первые символы Base64: PNG начинается с iVBORw0KGgo, PDF с JVBERi0, gzip с H4sI. Полный список есть в статье частые префиксы Base64. Откройте данные инструментом Base64 в файл: он определит формат и предложит скачать файл. Для H4sI воспользуйтесь декодером gzip Base64.

Декодирование даёт не те байты

Ошибки нет, но байты неправильные. Обычные причины:

  • Перевод строки в конце при кодировании. echo "hello" | base64 даёт aGVsbG8K (с \n), а echo -n "hello" | base64 даёт aGVsbG8=. Используйте printf '%s' или echo -n.
  • + превратился в пробел. В строках запроса URL и телах форм + означает пробел. URLSearchParams("t=PGI+Ym9sZDwvYj4=").get("t") возвращает PGI Ym9sZDwvYj4=. Одни декодеры после этого бросают исключение, другие выбрасывают пробел и выдают мусор. Прежде чем вставлять Base64 в URL, закодируйте его через encodeURIComponent или используйте Base64URL.
  • Оставшееся процентное кодирование. SGk%2FPg%3D%3D нужно сначала URL-декодировать в SGk/Pg==, а уже потом декодировать Base64.
  • Экранирование, скопированное из JSON. Если скопировать строку из сырого JSON, в неё может попасть буквальный \n (два символа). Нестрогий декодер Python отбрасывает обратную косую черту, оставляет n и без всякой ошибки возвращает неправильные байты: b64decode("SGVs\\nbG8=") даёт b'Hel\x9d\xb1\xbc'. Не копируйте из JSON, а разбирайте его. Декодер Base64 в JSON делает это для каждого поля.
  • Строгое и нестрогое отношение к пробелам. Python без validate=True, atob, .NET и MIME-декодер Java пропускают переносы строк. Python с validate=True и базовый декодер Java их отвергают. Данные MIME и PEM перенесены по 76 или 64 символа, так что выбирайте декодер, который это принимает.

Данные, закодированные дважды

Декодирование U0dWc2JHOGdkMjl5YkdRaA== даёт SGVsbG8gd29ybGQh, а это снова корректный Base64, который декодируется в Hello world!. Если результат декодирования состоит только из символов Base64 и его длина кратна 4, подозревайте двойное кодирование.

Часто такое случается с Secrets в Kubernetes. Значения в data: хранятся в Base64, и kubectl create secret --from-literal кодирует за вас. Если вы сначала закодируете значение сами, под получит вместо пароля его запись в Base64. Для обычных значений используйте stringData: или проверьте, что сохранено, декодером секретов Kubernetes. Если сомневаетесь, валидатор Base64 покажет, корректна ли строка и сколько байтов в ней содержится.

Вопросы и ответы

Как исправить binascii.Error: Incorrect padding?

Допишите =, пока длина не станет кратной 4: s += "=" * (-len(s) % 4). Если строка в Base64URL, также замените - на +, а _ на /, или используйте base64.urlsafe_b64decode.

Почему atob падает на JWT?

JWT используют Base64URL, где есть - и _. atob знает только + и /. Сначала замените символы или вставьте токен в декодер JWT.

Почему в декодированном тексте é вместо é?

Байты в UTF-8, но их прочитали как Latin-1 или Windows-1252. Декодируйте байты как UTF-8, например через TextDecoder в JavaScript или .decode("utf-8") в Python.

Можно ли починить строку Base64 длиной 4n+1?

Нет. Один лишний символ несёт всего 6 бит, меньше байта, значит, как минимум один символ потерян. Найдите исходный источник или проверьте, где строку обрезали.

Как понять, что данные закодированы в Base64 дважды?

Декодируйте один раз. Если результат снова состоит только из A-Z a-z 0-9 + / = и его длина кратна 4, декодируйте ещё раз.

Читайте также