YorozuyaIT
Japanese Text & Encoding

Python UnicodeDecodeError on Japanese Files: How to Tell Shift_JIS from UTF-8

Written by the Yorozuya IT editorial team, based in Japan. Menus, apps, and rules change, so check the date.

Short answer

You run open("data.csv").read() on a file from Japan and get this:

UnicodeDecodeError: 'utf-8' codec can't decode byte 0x83 in position 0: invalid start byte

The file is almost certainly not UTF-8. Python used UTF-8 by default, hit a byte that cannot start a UTF-8 character, and stopped.

Recognize the bytes

Japanese text mostly falls into two byte layouts. Look at the first non-ASCII byte:

Byte ranges for Shift_JIS and UTF-8: lead bytes 0x81-0x9F and 0xE0-0xFC versus 0xE3-0xE9 for kana and kanji

You can look at the raw bytes directly:

raw = open("data.csv", "rb").read(64)
print(raw)          # b'\x83A\x83C...'  -> Shift_JIS-looking
print(raw[:3] == b"\xef\xbb\xbf")   # True means UTF-8 with BOM

Pick the encoding

Valid UTF-8 has strict rules, so Japanese text that decodes as UTF-8 almost never does so by accident. CP932 is the opposite: it accepts most byte sequences. That is why the order matters.

def read_text(path):
    raw = open(path, "rb").read()
    for enc in ("utf-8-sig", "cp932"):
        try:
            return raw.decode(enc), enc
        except UnicodeDecodeError:
            continue
    raise ValueError("Unknown encoding; try charset-normalizer")

text, enc = read_text("data.csv")
print(enc)

With pandas:

import pandas as pd
df = pd.read_csv("data.csv", encoding="cp932")
# if a few bad bytes remain:
df = pd.read_csv("data.csv", encoding="cp932", encoding_errors="replace")

The silent failure

The reverse mistake does not always raise an error. Reading a UTF-8 file as cp932 often succeeds and gives you text like 譌・譛ャ隱. Your script runs, and your data is quietly wrong. So after you decode, print a sample and check that it reads as Japanese.

When you are not sure

Use a detector as a hint:

from charset_normalizer import from_path
best = from_path("data.csv").best()
print(best.encoding if best else None)

On the command line, nkf (a Japanese-origin tool) is handy. nkf -g data.csv guesses the encoding and nkf -w data.csv > utf8.csv converts to UTF-8. iconv -f CP932 -t UTF-8 in.csv > out.csv also works.

Quick checklist

FAQ

Is chardet or charset-normalizer reliable for short files?

Detection is statistical and gets weaker on short inputs. Treat it as a hint and verify the result by looking at the decoded text.

What about a file with a BOM?

A UTF-8 BOM (EF BB BF) means UTF-8. Use the utf-8-sig codec to read it so the BOM is not left in your first value.

How do I convert a whole file safely?

Decode with the correct source encoding, then write with a new encoding. Do not convert by decoding with a guessed one.

Keep reading