Python UnicodeDecodeError の直し方|0x93・cp932 をエラー文から逆引き
byte 0x93 などエラー文のバイト値から、ファイルの本当の文字コードを逆引きします。open・BOM・subprocess・pandas の原因別の直し方つき。
結論:UnicodeDecodeError: 'utf-8' codec can't decode の多くは、cp932(Shift_JIS)で保存されたファイルを UTF-8 として読んだことが原因です。その場合は open() に encoding="cp932" を足せば直ります。エラー文の byte 0x.. を見ると、どの文字コードのファイルだったかを当てられます。
1. 結論:エラー文からの逆引き表
| エラー文の一部 | 何が起きたか | 直し方 |
|---|---|---|
'utf-8' … 0x93・0x8c(漢字)、0x82(ひらがな)、0x83(カタカナ)、0x87(① など) | cp932 のファイルを UTF-8 で読んだ | encoding="cp932"(5章) |
'utf-8' … invalid continuation byte | cp932 の一部の漢字・半角カナ | encoding="cp932"(5章) |
'utf-8' … 0xff in position 0 | UTF-16 のファイル | encoding="utf-16" |
'utf-8' … unexpected end of data | UTF-8 が途中で切れている/cp932 の半角カナ | ファイルを確認・encoding="cp932" を試す(3章) |
'cp932' … 0xef in position 0 | BOM 付き UTF-8 を cp932 で読んだ | encoding="utf-8-sig"(5章) |
'cp932' … 0x98 など | UTF-8 を cp932 で読んだ | encoding="utf-8"(4章) |
'shift_jis' … illegal multibyte sequence | shift_jis に無い文字(髙・①) | encoding="cp932"(6章) |
'NoneType' object has no attribute 'strip' | subprocess の text=True(直前に UnicodeDecodeError が出ている) | encoding="cp932"(5章) |
3.15 からは encoding 省略の open() が cp932 ではなく UTF-8 で読むため(PEP 686)、3.14 で動いたコードでも出ます(点検はPython 3.15 の変更点と確認5点)。
2. エラー文の読み方:止まるのは読み込む行
cp932 で保存した CSV を、3.15.0 で encoding なしで読みました。
import csv
with open("sjis.csv", newline="") as f:
for row in csv.reader(f):
print(row)
Traceback (most recent call last):
File "...\read_csv.py", line 4, in <module>
for row in csv.reader(f):
~~~~~~~~~~^^^
File "<frozen codecs>", line 325, in decode
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x93 in position 0: invalid start byte
例外が出たのは open() の3行目ではなく、中身を読む4行目です。直すのは指された行の少し上の open() です。
'utf-8' codec:Python が使った文字コード(ファイルの文字コードではない)byte 0x93:読めなかったバイト。3章の表で元の文字を当てるposition 0:先頭から何バイト目か。英数字の後ろに「院長」がある cp932 の CSV ではbyte 0x89 in position 21だった
encoding="cp932" を足すと、3.15.0 で ['2026/09/01', 'トヨタ自動車', '12000'] などと正しく表示されました。
3. バイト値から元の文字コードを当てる
文字コードごとのバイト列です(両版で同じ)。
| 文字 | cp932 | UTF-8 | UTF-16 |
|---|---|---|---|
| あ | 82 a0 | e3 81 82 | ff fe 42 30 |
| ア | 83 41 | e3 82 a2 | ff fe a2 30 |
| 日 | 93 fa | e6 97 a5 | ff fe e5 65 |
| 経 | 8c 6f | e7 b5 8c | ff fe 4c 7d |
| ① | 87 40 | e2 91 a0 | ff fe 60 24 |
byte 0x93 なら、「日」「東」「電」など先頭バイトが 0x93 の漢字で始まる cp932 のファイルだと読めます。0x93 で始まる漢字は多数あり、1文字には絞れません。0x8c も「経」「計」「県」などに共通で、「経路をトレースしています」を cp932 で保存して読むと 0x8c でした。UTF-16 の列は先頭の BOM(ff fe)込みで、UTF-8 の BOM は ef bb bf です。
末尾の語は、次の入力で出ました。
invalid start byte:0x80〜0x9F で始まる cp932 の文字(院 89 40 など)、UTF-16 の0xffinvalid continuation byte:0xE0〜0xEF で始まる cp932 の漢字(乕 e5 68 →0xe5)、半角カナ(データ →0xc3)unexpected end of data:末尾が切れた UTF-8(bytes in position 6-7)、半角カナ「テスト」
4. 'cp932' codec can't decode(illegal multibyte sequence)が出たとき
'cp932' codec can't decode は、UTF-8 などのファイルを cp932 で読んだときに出ます。3.14.7 で encoding を省略して読んだ結果です。
| ファイル | エラー文(3.14.7) |
|---|---|
| UTF-8 | byte 0x98 in position 5 |
| BOM 付き UTF-8 | byte 0xef in position 0 |
| UTF-16 | byte 0x98 in position 8 |
| 末尾が切れた UTF-8 | 例外なし・'譌・譛ャ隱' |
例外が出た3つは、末尾が illegal multibyte sequence です。0x98 は「付」の UTF-8(e4 bb 98)の3バイト目ですが、UTF-16 でも 0x98 が出たので、これだけでは UTF-8 と決められません。3.15.0 では UTF-8 の2つは省略で読めました。
5. 原因別の直し方:open・BOM・subprocess
open()・Path.read_text():encoding を書く
from pathlib import Path
with open("sjis.csv", encoding="cp932", newline="") as f:
text = f.read()
text = Path("sjis.csv").read_text(encoding="cp932")
Path.read_text() も省略すると 3.15.0 で止まりました。書き出し側の使い分けは3.15 記事の5章にあります。
BOM 付き UTF-8:KeyError '日付' の正体
BOM 付き UTF-8 の CSV を encoding="utf-8" で csv.DictReader に渡すと、例外は出ません。先頭の列名が '\ufeff日付'(BOM の文字 U+FEFF 付き)になり、row["日付"] が KeyError: '日付' になりました(3.15.0)。encoding="utf-8-sig" なら列名は '日付' になります。
subprocess:AttributeError に化けて出る
日本語 Windows の cmd /c echo 日本語 の出力(cp932)を、text=True だけで受けた結果です。
| 書き方 | 3.15.0 の結果 |
|---|---|
run(..., text=True) | 裏で UnicodeDecodeError、stdout は None |
Popen/check_output(text=True) | その場で UnicodeDecodeError |
encoding="cp932" | '日本語'(3.14.7 も同じ) |
run() は例外を表示するだけで先へ進みます。
Exception in thread Thread-1 (_readerthread):
...
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x93 in position 0: invalid start byte
Traceback (most recent call last):
File "...\sp.py", line 4, in <module>
print(out.stdout.strip())
^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'strip'
最後の AttributeError だけでは、文字コードが原因だと気づけません。text=True の代わりに encoding を渡して直します。
import subprocess
out = subprocess.run(["cmd", "/c", "echo", "日本語"],
capture_output=True, encoding="cp932")
print(out.stdout.strip()) # 日本語
Windows 以外でも動かすなら platform.system() で分けます。当サイトのネットワークスキャナーは、arp と tracert の出力を読む2か所をこの書き方にしています。一部が読めなくても止まらないよう errors="replace" も併用しています(正しい encoding を指定したうえでの保険)。
errors="replace"・"ignore" は直ったのではない
errors= を付けると例外は消えますが、データは読めていません。cp932 の CSV を encoding="utf-8" で読んだ先頭です(3.14.7・3.15.0 で同じ)。
errors="replace":'���t,����,���z\n2026/'errors="ignore":'t,,z\n2026/09/01,g^,1'
"ignore" は日本語を黙って消します。「トヨタ自動車」が g^ になっても例外は出ません。subprocess に errors="replace" を付けた場合も、3.15.0 では '���{��' でした。
6. pandas の read_csv で出たとき
pd.read_csv() の既定は Python の版に関係なく UTF-8 なので、3.15 で新しく壊れるわけではありません。cp932 の CSV は 0x93 invalid start byte で止まり、encoding="cp932" で読めました(pandas 3.0.6・Python 3.14.7)。
- shift_jis ではなく cp932:「髙橋,①」を含む CSV は
"shift_jis"だと'shift_jis' codec can't decode byte 0xee in position 10で止まり、"cp932"では読めた - BOM 付き UTF-8 は既定で読め、BOM は自動で除かれた。UTF-16 は
encoding="utf-16"が必要
見出し行や桁区切りも直す実例は証券会社のCSVをpandasで読み込むにあります。
7. 文字コードが分からないとき
候補を順に試し、最初に読めた文字コードを使います。
def read_text_auto(path, encodings=("utf-8-sig", "cp932")):
for enc in encodings:
try:
with open(path, encoding=enc) as f:
return enc, f.read()
except UnicodeDecodeError:
continue
raise ValueError("どの文字コードでも読めませんでした")
3.15.0 では cp932 の CSV が cp932、UTF-8 は BOM の有無にかかわらず utf-8-sig で読めました。utf-8-sig は BOM なしも読めるので、"utf-8" は候補に要りません。
utf-8-sigを cp932 より先に置く:cp932 は UTF-8 を文字化けしたまま読めてしまうことがある(4章の末尾切れの例)- UTF-16 は候補外:UTF-16 のファイルは ValueError になった。扱うなら
"utf-16"を足す
当サイトのCSVデータビューア・エディタは、utf-8 → cp932 → latin-1 の順に read_csv() を試します。
推測ライブラリの chardet・charset-normalizer は、今回 17 バイト以上の検体では当たり、短いとライブラリによっては外れました。cp932 の「日付」だけ(4バイト)を charset-normalizer は big5hkscs、半角「テスト」(3バイト)を chardet は信頼度 0.99 で utf-8 と答えました。推測結果は中身を目で確かめてから使ってください。
8. 一時しのぎ:-X utf8=0 と PYTHONUTF8=0
起動時に UTF-8 モードを切ると、3.15 でも 3.14 までの動きに戻ります。3.15.0 では省略の open() で cp932 の CSV も subprocess の「日本語」も読めました。
python -X utf8=0 app.py
ただし恒久的な対策ではありません。設定していない PC や起動方法では UTF-8 に戻ります。環境変数 PYTHONUTF8=0 を使う方法は3.15 記事の「一時的に元へ戻す」にあります。
9. 危ない行を先に探す:-X warn_default_encoding
3.14 でも使えるので、エラーが出る前に encoding の省略箇所を洗い出せます。警告は2章の Traceback と違い、直すべき open() の3行目を指しました(3.14.7・3.15.0)。
python -X warn_default_encoding read_csv.py
出た警告の追い方は3.15 記事の4章にあります。
10. よくある質問(FAQ)
Q. errors="ignore" を付けたらエラーが消えました。これで直りましたか?
直っていません。日本語が黙って消えます(5章の実測で「トヨタ自動車」が g^)。正しい encoding を指定してください。
Q. encoding="locale" と書いても読めますか?
日本語 Windows では読めます(3.15.0 で cp932 の CSV を読めました)。OS による違いは3.15 記事の5章にあります。
Q. Mac や Linux でも出ますか?
cp932 のファイルを UTF-8 で読めば、OS に関係なく出ます。3.15 の変更で増えるのは主に Windows です(PEP 686)。
本記事は、生成AIを活用して下書きし、運営者が内容を確認・編集したうえで公開しています。AIの利用方針は免責事項をご覧ください。
11. まとめ
'utf-8'…0x93などは cp932 を UTF-8 で読んだサイン。encoding="cp932"を足す0xffは UTF-16、BOM 付き UTF-8 は"utf-8-sig"。subprocess はencoding="cp932"を渡すerrors=も-X utf8=0も一時しのぎ
直ったら次はこちら。
- 再発を防ぐ点検:Python 3.15 の変更点と確認5点
- CSV を pandas で集計:証券会社のCSVをpandasで読み込む
open()の基本:Python基本文法のファイル操作
短い説明はPythonエラー辞典の UnicodeDecodeErrorへ。
PEP 686/What's New in Python 3.15/codecs のエラーハンドラ。実測は Windows 11(コードページ 932)の Python 3.14.7 と 3.15.0 です。3.15.0 は公式の embeddable 版(zip)で、インストーラー版では試していません。pandas 3.0.6・chardet 7.6.0・charset-normalizer 3.5.2 は 3.14.7 だけです。