エラーメッセージの一覧
| メッセージ | 表示される場所 | 最も考えられる原因 |
|---|---|---|
binascii.Error: Incorrect padding | Python の base64.b64decode | 末尾の = の不足。Base64URL や途中で切れた文字列によることが多い |
binascii.Error: Invalid base64-encoded string: number of data characters (5) cannot be 1 more than a multiple of 4 | Python | 入力が途中で切れている、または -/_ が黙って捨てられた |
binascii.Error: Only base64 data is allowed | validate=True を付けた Python | 入力に改行、スペース、-、_ が含まれている |
InvalidCharacterError: Failed to execute 'atob' on 'Window': The string to be decoded is not correctly encoded. | Chrome、Edge | Base64URL の文字、ゴミ文字、長さの誤り |
InvalidCharacterError: String contains an invalid character | Firefox | 同上 |
InvalidCharacterError: Invalid character | Node.js の atob | 同上 |
IllegalArgumentException(“Illegal base64 character …") | Java の java.util.Base64 | アルファベットに合わないデコーダー、または改行 |
FormatException | .NET の Convert.FromBase64String | Base64URL の文字、またはパディングの不足 |
base64: invalid input | GNU coreutils の base64 -d | アルファベット外の文字 |
デコーダーのエラーを直す
Python の「Incorrect padding」
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 の倍数より 1 多い場合は、パディングでは解決できません。このとき Python は number of data characters (5) cannot be 1 more than a multiple of 4 を報告します。余った 1 文字は 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:接頭辞、URL エンコードによる%2Fなどです。
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 の修復 ツールは同じクリーンアップを行い、何を変更したかを教えてくれます。
Java の「Illegal base64 character」と .NET の FormatException
Java の java.util.Base64 には 3 つのデコーダーがあり、それぞれ自分のアルファベットに厳格です。メッセージは問題の文字を 16進数で示します。5f は _、2d は -、2f は /、20 はスペース、a は改行です。
| 入力に含まれるもの | 使うデコーダー |
|---|---|
+ と / | Base64.getDecoder() |
- と _ | Base64.getUrlDecoder() |
| 改行(MIME、PEM の本文) | Base64.getMimeDecoder() |
基本のデコーダーは改行とスペースを拒否しますが、パディングの不足は受け付けるので、SGVsbG8 は問題なくデコードされます。
.NET の Convert.FromBase64String は、Base64URL の文字やパディングの不足に対して FormatException をスローします。スペースと改行は読み飛ばします。呼び出す前に、上で示したようにアルファベットとパディングを直してください。完全な例は Java での Base64 と C# での Base64 にあります。
テキストが文字化けする
デコードは成功したのに、テキストがおかしく見える場合です。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\0 | Hello | UTF-16LE のバイト列を UTF-8 として読んだ |
1 行目は atob の典型的な罠です。atob は 1 バイトを 1 文字に対応させるため、atob("Q2Fmw6k=") は "Café" を返します。代わりにバイト列を UTF-8 としてデコードしてください。
const bytes = Uint8Array.from(atob("Q2Fmw6k="), (c) => c.charCodeAt(0));
new TextDecoder().decode(bytes); // "Café"
UTF-16LE は Windows のツールでよく見かけます。PowerShell の -EncodedCommand や多くの .NET API がこれを生成します。Base64 からテキストへの変換 では正しく読めるまで文字コードを切り替えられ、Base64 から UTF-16 はワイド文字のケースを扱います。
出力がバイナリのように見える
デコード結果が � や制御文字だらけだったり、PNG、PK、%PDF といった断片が含まれていたりするなら、ペイロードはファイルです。Base64 の先頭の文字を見てください。iVBORw0KGgo なら PNG、JVBERi0 なら PDF、H4sI なら gzip です。一覧は よくある Base64 の接頭辞 にあります。データは、形式を判定してダウンロードできる Base64 からファイルへの変換 で開いてください。H4sI には gzip Base64 のデコード を使います。
デコード結果が期待と異なるバイト列になる
エラーは出ないのに、バイト列が違う場合です。よくある理由は次のとおりです。
- エンコード時の末尾の改行。
echo "hello" | base64は(\n付きの)aGVsbG8Kになり、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は、Base64 としてデコードする前に URL デコードしてSGk/Pg==に戻す必要があります。 - JSON からコピーしたエスケープ。 生の JSON から文字列をコピーすると、リテラルの
\n(2 文字)が紛れ込むことがあります。Python の寛容なデコーダーはバックスラッシュを捨ててnを残し、エラーなしで誤ったバイト列を返します。b64decode("SGVs\\nbG8=")はb'Hel\x9d\xb1\xbc'になります。コピーするのではなく、JSON をパースしてください。JSON Base64 デコーダー はすべてのフィールドに対してこれを行います。 - 空白の扱いが厳格か寛容か。
validate=Trueなしの Python、atob、.NET、Java の MIME デコーダーは改行を読み飛ばします。validate=True付きの Python と Java の基本のデコーダーは改行を拒否します。MIME と PEM のデータは 76 文字か 64 文字で折り返されているので、それを受け付けるデコーダーを選んでください。
二重にエンコードされたデータ
U0dWc2JHOGdkMjl5YkdRaA== をデコードすると SGVsbG8gd29ybGQh になり、これも有効な Base64 で、デコードすると Hello world! になります。1 回デコードした結果が Base64 の文字だけで構成され、長さが 4 の倍数なら、二重エンコードを疑ってください。
Kubernetes Secret でよく起こります。data: の下の値は Base64 で、kubectl create secret --from-literal はエンコードを代わりに行ってくれます。先に自分で値をエンコードしてしまうと、Pod にはパスワードではなく Base64 のテキストが渡ります。平文の値には stringData: を使うか、Kubernetes Secret デコーダー で保存内容を確認してください。迷ったときは、Base64 バリデーター で文字列が有効かどうかと、何バイトのデータを含むかを確認できます。
よくある質問
binascii.Error: Incorrect padding を解消するには?
長さが 4 の倍数になるまで = を付け足します:s += "=" * (-len(s) % 4)。文字列が Base64URL なら、さらに - を + に、_ を / に置き換えるか、base64.urlsafe_b64decode を使ってください。
JWT を atob でデコードすると失敗するのはなぜですか?
JWT は - と _ を含む Base64URL を使いますが、atob が知っているのは + と / だけだからです。先に文字を変換するか、トークンを JWT デコーダー に貼り付けてください。
デコードしたテキストが é ではなく é と文字化けするのはなぜですか?
バイト列は UTF-8 なのに、Latin-1 や Windows-1252 として読まれたためです。JavaScript なら TextDecoder、Python なら .decode("utf-8") などで、バイト列を UTF-8 としてデコードしてください。
長さが 4n+1 の Base64 文字列は修復できますか?
できません。余った 1 文字は 6 ビットしか持たず 1 バイトに満たないので、少なくとも 1 文字が欠けています。元のデータを探すか、文字列がどこで切れたかを確認してください。
データが二重に Base64 エンコードされているかどうかを見分けるには?
一度デコードしてみてください。結果が再び A-Z a-z 0-9 + / = だけからなる、長さが 4 の倍数の文字列なら、もう一度デコードします。