UNICODEDECODEERROR

Python UnicodeDecodeError の直し方|0x93・cp932 をエラー文から逆引き

byte 0x93 などエラー文のバイト値から、ファイルの本当の文字コードを逆引きします。open・BOM・subprocess・pandas の原因別の直し方つき。

🎯 対象: UnicodeDecodeError で止まった Windows の初心者〜初級者 ⏱️ 読了: 約8分 🧪 実測: Windows 11(コードページ 932)・Python 3.14.7/3.15.0(embeddable 版)・2026-10-13

結論: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 bytecp932 の一部の漢字・半角カナencoding="cp932"(5章)
'utf-8' … 0xff in position 0UTF-16 のファイルencoding="utf-16"
'utf-8' … unexpected end of dataUTF-8 が途中で切れている/cp932 の半角カナファイルを確認・encoding="cp932" を試す(3章)
'cp932' … 0xef in position 0BOM 付き UTF-8 を cp932 で読んだencoding="utf-8-sig"(5章)
'cp932' … 0x98 などUTF-8 を cp932 で読んだencoding="utf-8"(4章)
'shift_jis' … illegal multibyte sequenceshift_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. バイト値から元の文字コードを当てる

文字コードごとのバイト列です(両版で同じ)。

文字cp932UTF-8UTF-16
あ82 a0e3 81 82ff fe 42 30
ア83 41e3 82 a2ff fe a2 30
日93 fae6 97 a5ff fe e5 65
経8c 6fe7 b5 8cff fe 4c 7d
①87 40e2 91 a0ff 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 の 0xff
  • invalid 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-8byte 0x98 in position 5
BOM 付き UTF-8byte 0xef in position 0
UTF-16byte 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エラー辞典の UnicodeDecodeErrorへ。

📌
参考にした一次情報と検証環境(2026年10月13日実測)

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 だけです。