- Python
UnicodeDecodeErrorの原因と直し方|cp932・utf-8・BOM
UnicodeDecodeError は、ファイルを「実際とは違う文字コード」で読もうとしたときに出るエラーです。 日本語の環境では、ほとんどが Shift_JIS(Windows では cp932)と UTF-8 の取り違えです。
| エラー文 | 起きていること | 直し方 |
|---|---|---|
'utf-8' codec can't decode byte 0x8e in position 3: invalid start byte |
Shift_JIS(cp932)のファイルを UTF-8 で読んだ | encoding="cp932" |
'cp932' codec can't decode byte 0x8e in position 30: illegal multibyte sequence |
UTF-8 のファイルを cp932 で読んだ(Windows の既定) | encoding="utf-8" |
'utf-8' codec can't decode byte 0xff in position 0: invalid start byte |
UTF-16 のファイル(Excel の「Unicode テキスト」など)を読んだ | encoding="utf-16" |
'shift_jis' codec can't decode byte 0xee |
機種依存文字(①・髙など)を shift_jis で読んだ |
encoding="cp932" |
UnicodeEncodeError: 'cp932' codec can't encode character '\U0001f363' |
書き込み・表示のときに、cp932 に無い文字(絵文字など)があった | encoding="utf-8" で書く |
読むときは「ファイルの本当の文字コード」を encoding= に書くのが唯一の正しい直し方です。 この記事では、それぞれのエラーを実際に起こし、出たメッセージと直し方を並べました。
確認環境:Ubuntu 24.04、Python 3.13.7、pandas 3.0.6、charset-normalizer 3.5.2(確認日 2026年10月10日)。Windows の既定の文字コードに関する部分は、Python 公式ドキュメントと PEP 686 で確認しています。
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「UnicodeDecodeErrorの原因と直し方|cp932・utf-8・BOM」
エラー文の読み方
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x8e in position 3: invalid start byte
~~~~~ ~~~~ ~
読もうとした文字コード 読めなかったバイト 先頭から何バイト目(0始まり)
| 部分 | 分かること |
|---|---|
'utf-8' |
Python が使った文字コード。指定していないなら OS の既定(Windows は cp932、macOS・Linux は UTF-8) |
byte 0x8e |
読めなかったバイト。0x81〜0x9f・0xe0〜0xef なら Shift_JIS の1バイト目によく出る値。0xff・0xfe が先頭なら UTF-16 |
position 3 |
ファイルの先頭から何バイト目か。この位置の前後を見ると、どの文字で引っかかったか分かる |
例1:Shift_JIS(cp932)のCSVを UTF-8 で読んだ
Excel で保存した「CSV(コンマ区切り)」や、業務システムが出力するCSVは、Shift_JIS(cp932)のことが多くあります。macOS・Linux の Python は既定で UTF-8 として読むため、エラーになります。
open("sjis.csv").read() # macOS・Linux の既定は UTF-8
UnicodeDecodeError: 'utf-8' codec can't decode byte 0x8e in position 3: invalid start byte
直し方:encoding="cp932" を指定します。
with open("sjis.csv", encoding="cp932", newline="") as f:
print(f.read())
id,氏名,住所
1,髙橋一郎,東京都①丁目
2,山田花子,大阪府
shift_jis ではなく cp932 を指定する
Python の shift_jis は規格どおりの Shift_JIS で、Windows で使われる機種依存文字(①・㈱・Ⅰ・髙・﨑など)を含みません。同じファイルを shift_jis で読むと、① のところでエラーになりました。
UnicodeDecodeError: 'shift_jis' codec can't decode byte 0xee in position 15: illegal multibyte sequence
| 文字 | shift_jis |
cp932 |
euc_jp |
|---|---|---|---|
| ① ㈱ Ⅰ ⅰ | × | ○ | × |
| 髙(はしご高)・﨑(たつさき) | × | ○ | × |
| ~(全角チルダ U+FF5E) | × | ○ | × |
| —(ダッシュ U+2014)・絵文字 | × | × | × |
Windows で作られた「Shift_JIS」のファイルは、cp932 で読むのが安全です。 cp932 は shift_jis の文字をすべて含みます。
例2:UTF-8 のファイルを cp932 で読んだ(Windows)
Windows の Python 3.14 までは、encoding を省略すると cp932 で読みます。VS Code などで作った UTF-8 のファイルや、Web からダウンロードしたファイルを読むとエラーになります。
UnicodeDecodeError: 'cp932' codec can't decode byte 0x8e in position 30: illegal multibyte sequence
(確認環境は Linux なので、encoding="cp932" を指定して同じ状況を作りました)
直し方:encoding="utf-8" を指定します。open() には常に encoding= を書くと、Windows・macOS・Linux のどこで動かしても同じ結果になります。
| Python のバージョン | Windows で encoding を省略したとき |
|---|---|
| 3.14 まで | ロケールの文字コード(日本語の Windows は cp932) |
| 3.15 以降 | UTF-8(PEP 686 で UTF-8 モードが既定になる) |
| 3.7 以降で UTF-8 にそろえたいとき | 環境変数 PYTHONUTF8=1 か、python -X utf8 で起動 |
3.15 以降で以前の動きに戻すときは PYTHONUTF8=0 です。OS の文字コードを知りたいときは、UTF-8 モードに影響されない locale.getencoding()(3.11 以降)を使います。
例3:BOM 付き UTF-8 で、列名が見つからない(KeyError)
Excel の「CSV UTF-8(コンマ区切り)」で保存したファイルは、先頭に BOM(EF BB BF の3バイト)が付きます。encoding="utf-8" で読むとエラーにはなりませんが、1列目の名前の先頭に が付き、列名で取り出せなくなります。
import csv
with open("utf8bom.csv", encoding="utf-8", newline="") as f:
row = next(csv.DictReader(f))
print(list(row.keys()))
print(row["id"])
['id', '氏名', '住所']
KeyError: 'id'
直し方:encoding="utf-8-sig" で読みます。BOM があれば取り除き、無ければそのまま UTF-8 として読むので、UTF-8 のファイルは utf-8-sig で読むと決めておくと安全です。
['id', '氏名', '住所'] ← utf-8-sig で読んだ結果
pandas の read_csv() は既定で BOM を取り除くため、この問題は起きませんでした(列名は ['id', '氏名', '住所'])。
例4:UTF-16 のファイル(先頭が 0xff)
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 0: invalid start byte
position 0 で 0xff または 0xfe なら、UTF-16 のファイルです。Excel の「Unicode テキスト」で保存したファイル、Windows の PowerShell 5.1 で > を使って出力したファイルなどが UTF-16 になります。
with open("utf16.txt", encoding="utf-16") as f: # BOM(FF FE)で並び順も判定される
print(f.readline())
id 氏名 住所
position 0 で 0x50 0x4b(PK)なら zip 形式(.xlsx など)、0x1f 0x8b なら gzip です。テキストではないので、openpyxl や gzip.open() など、その形式用の読み方をします。
例5:書き込み・表示で UnicodeEncodeError
読むときではなく、書くとき・print() するときに出るのが UnicodeEncodeError です。cp932 に無い文字を cp932 で書こうとすると出ます。
UnicodeEncodeError: 'cp932' codec can't encode character '\U0001f363' in position 2: illegal multibyte sequence ← 「寿司🍣」の絵文字
UnicodeEncodeError: 'cp932' codec can't encode character '—' in position 0: illegal multibyte sequence ← ダッシュ「—」
UnicodeEncodeError: 'shift_jis' codec can't encode character '①' in position 0: illegal multibyte sequence ← 「①」
| 場面 | 直し方 |
|---|---|
| ファイルに書く | open(..., "w", encoding="utf-8")。Excel で開くCSVなら encoding="utf-8-sig" |
Windows で print() してリダイレクトした |
PYTHONUTF8=1 で起動するか、sys.stdout.reconfigure(encoding="utf-8") |
| どうしても cp932 で出力する(取引先の指定など) | errors="replace" で ? に置き換える。置き換えた件数をログに残す |
cp932 で書いて読み直すと、文字が変わることがある
cp932 は、見た目が同じ別の文字を1つにまとめて保存します。確認環境で書いて読み直すと、次の2文字が変わりました。
| 元の文字 | cp932 で書いて読み直すと | 影響 |
|---|---|---|
| 〜(波ダッシュ U+301C) | ~(全角チルダ U+FF5E) | 文字列の比較・検索で一致しなくなる |
| −(マイナス記号 U+2212) | -(全角ハイフンマイナス U+FF0D) | 同上 |
UTF-8 のデータを cp932 のCSVに出して取り込み直す処理では、この変化で「同じはずのデータが一致しない」ことが起きます。
文字コードが分からないときに調べる
ファイルの文字コードが分からないときは、よく使われる文字コードで順に読んでみて、どれで読めるかを見るのが確実です。次のスクリプトは、読めなかった位置と前後のバイトも表示します。
"""ファイルがどの文字コードで読めるかを調べる: python check_encoding.py ファイル名"""
import sys
CANDIDATES = ["utf-8-sig", "utf-8", "cp932", "euc_jp", "utf-16"]
def check(path):
data = open(path, "rb").read()
print(f"{path}: {len(data)} bytes, 先頭 {data[:4].hex(' ')}")
for enc in CANDIDATES:
try:
text = data.decode(enc)
except UnicodeDecodeError as e:
line = data.count(b"\n", 0, e.start) + 1
print(f" {enc:10} NG position {e.start}({line}行目): {data[max(0, e.start-4):e.start+4].hex(' ')}")
else:
print(f" {enc:10} OK 1行目: {text.splitlines()[0][:30]!r}")
for p in sys.argv[1:]:
check(p)
$ python check_encoding.py sjis.csv utf16.txt
sjis.csv: 55 bytes, 先頭 69 64 2c 8e
utf-8-sig NG position 3(1行目): 69 64 2c 8e 81 96 bc
utf-8 NG position 3(1行目): 69 64 2c 8e 81 96 bc
cp932 OK 1行目: 'id,氏名,住所'
euc_jp NG position 3(1行目): 69 64 2c 8e 81 96 bc
utf-16 NG position 34(2行目): 87 40 92 9a 96 da 0a 32
utf16.txt: 70 bytes, 先頭 ff fe 69 00
utf-8-sig NG position 0(1行目): ff fe 69 00
utf-8 NG position 0(1行目): ff fe 69 00
cp932 NG position 31(2行目): 6a 00 4e ce 90 09 00 71
euc_jp NG position 0(1行目): ff fe 69 00
utf-16 OK 1行目: 'id\t氏名\t住所'
「OK」が出て、1行目が正しく読めている文字コードが答えです。 短いファイルでは複数の文字コードで「OK」になることがあるので、1行目の中身も確認します。
推定ライブラリの charset-normalizer(pip install charset-normalizer)でも調べられます。確認環境では4つのファイルとも正しく判定されました。
from charset_normalizer import from_path
print(from_path("sjis.csv").best().encoding) # → cp932
推定は、ファイルが短い・英数字ばかりのときに外れることがあります。業務で受け取るファイルは、文字コードを仕様として決めてもらうのが確実です。
errors= で読み飛ばすのは最後の手段
open("sjis.csv", encoding="utf-8", errors="replace").readline()
# → 'id,����,�Z��\n' ← 読めない部分が � に置き換わる
open("sjis.csv", encoding="utf-8", errors="backslashreplace").readline()
# → 'id,\\x8e\\x81\\x96\\xbc,\\x8fZ\\x8f\\x8a\n'
errors= |
動き | 使ってよい場面 |
|---|---|---|
"strict"(既定) |
エラーにする | 通常はこれ |
"replace" |
読めない部分を �(書くときは ?)にする |
ログの表示など、内容が多少欠けてもよいとき |
"backslashreplace" |
\x8e のように残す |
どこが読めないかを調べるとき |
"ignore" |
読めない部分を黙って捨てる | データの処理には使わない(欠けたことに気づけない) |
errors="replace" でエラーを消しても、文字コードの指定が間違っている状態は変わりません。上の例のように、日本語がすべて読めなくなります。
pandas と Excel 向けのCSV
import pandas as pd
df = pd.read_csv("sjis.csv", encoding="cp932") # Shift_JIS(cp932)のCSVを読む
df.to_csv("for_excel.csv", index=False, encoding="utf-8-sig") # Excel でそのまま開けるCSV
| 用途 | encoding |
|---|---|
| Excel で保存した「CSV(コンマ区切り)」を読む | cp932 |
| Excel で保存した「CSV UTF-8」を読む | utf-8-sig(pandas は utf-8 でも可) |
| Excel でダブルクリックして開くCSVを書く | utf-8-sig(BOM が無いと Excel が文字化けする) |
| 他のシステムに渡すCSVを書く | 相手の仕様に合わせる(UTF-8 の BOM の有無も確認) |
よくある質問
Q. 同じプログラムが、Mac では動くのに Windows でエラーになります。
A. open() の encoding を省略していると、Mac は UTF-8、Windows(Python 3.14 まで)は cp932 で読むためです。encoding="utf-8" のように明示すると、どちらでも同じ動きになります。
Q. encoding="cp932" を指定しても、別の位置でエラーになります。
A. ファイルの途中から文字コードが変わっている(複数のファイルを連結した、一部の行だけ別のシステムで追記した)ことがあります。上の調べるスクリプトで位置と行を確認し、その行の出どころを調べます。
Q. 文字化けはしていないのに、文字列の比較が一致しません。
A. BOM()が付いている、または cp932 を経由して 〜 が ~ に変わっている可能性があります。repr() で表示すると、見えない文字や別の文字が分かります。
Q. encoding="shift_jis" と encoding="cp932" はどちらを使えばよいですか。
A. Windows で作られたファイルなら cp932 です。shift_jis は①や髙などの機種依存文字を含まないため、読み書きの途中でエラーになることがあります。
まとめ
UnicodeDecodeErrorは、実際とは違う文字コードで読んだエラー。'utf-8' ... 0x8eなら Shift_JIS、0xff in position 0なら UTF-16- Shift_JIS のファイルは
cp932で読む。shift_jisは①・髙などで止まる - UTF-8 のファイルは
utf-8-sigで読むと、BOM があってもなくても同じに扱える open()には常にencoding=を書く。Windows は 3.14 まで cp932、3.15 から UTF-8 が既定- 書くときの
UnicodeEncodeErrorは、cp932 に無い文字。UTF-8 で書く。Excel 向けはutf-8-sig errors="ignore"はデータの処理に使わない
参考・出典
確認日はいずれも 2026年10月10日です。
- Python 3 ドキュメント「codecs — 標準エンコーディング」:https://docs.python.org/ja/3/library/codecs.html#standard-encodings
- Python 3 ドキュメント「組み込み関数 open()」:https://docs.python.org/ja/3/library/functions.html#open
- PEP 686「Make UTF-8 mode default」:https://peps.python.org/pep-0686/
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「UnicodeDecodeErrorの原因と直し方|cp932・utf-8・BOM」
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。