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期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

RJCで一緒に開発しながら、 成長を楽しみませんか?