Home › Errors › UnicodeEncodeError
UnicodeEncodeError: 'utf-8' codec can't encode character
Exception: UnicodeEncodeErrorCategory: runtime (encoding)Raised at: the write or print that tried to encode a character the target codec cannot represent
What this error means
You tried to turn text into bytes using a codec that cannot represent one of the characters. Note the direction: encode means text → bytes, which is the opposite of the UnicodeDecodeError people meet more often.
Traceback (most recent call last):
File "demo.py", line 2, in <module>
print("price: ₹100")
UnicodeEncodeError: 'ascii' codec can't encode character '\u20b9' in position 8: ordinal not in range(128)
Three parts of the message matter: the codec that failed, the character it could not handle (shown as an escape), and the position. Together they identify the problem precisely.
Why utf-8 in the message is almost never the real culprit
This is the confusing part, and it is worth being precise. UTF-8 can encode every Unicode character that exists. So a genuine 'utf-8' codec can't encode character error is rare, and usually means one of two narrow things: a lone surrogate, or a codec that is *named* utf-8 but is not really being used.
# 1 — a lone surrogate, which UTF-8 genuinely cannot encode
bad = '\ud800' # half of a surrogate pair
bad.encode('utf-8') # 💥 'utf-8' codec can't encode
# character '\ud800'
# this usually comes from decoding with errors='surrogateescape'
# or from a broken source; fix the source, not the encoder
# 2 — the message says ascii or cp1252, which is the common real case
'₹'.encode('ascii') # 💥 'ascii' codec can't encode
'₹'.encode('cp1252') # 💥 'cp1252' codec can't encode
'₹'.encode('utf-8') # ✅ b'\xe2\x82\xb9' — utf-8 is fine
So when you see this error, read the codec name first. If it says ascii or cp1252 or latin-1, the problem is that the target encoding is too narrow — not that your text is unusual.
The Windows console case
The most common real-world report. On Windows the console historically defaults to a legacy code page such as cp1252, so printing non-Latin text fails even though the file itself is fine:
# ❌ crashes on a cp1252 console
print("कीमत: ₹100")
# ✅ tell Python explicitly which encoding to use
import sys
sys.stdout.reconfigure(encoding="utf-8") # Python 3.7+
print("कीमत: ₹100")
# or set it for the whole process before Python starts
# set PYTHONIOENCODING=utf-8 (cmd)
# $env:PYTHONIOENCODING="utf-8" (PowerShell)
# Windows Terminal and modern PowerShell 7 default to UTF-8 already
sys.stdout.reconfigure is the clean fix when you control the program. Setting PYTHONIOENCODING is better when you do not, because it fixes the behaviour for every script in that environment.
Writing to a file
The second most common case. The default encoding for open() is platform-dependent, so code that works on macOS or Linux fails on Windows:
# ❌ uses the platform default — cp1252 on Windows
with open("out.txt", "w") as f:
f.write("कीमत: ₹100") # 💥 on a cp1252 system
# ✅ always state the encoding
with open("out.txt", "w", encoding="utf-8") as f:
f.write("कीमत: ₹100") # works everywhere
# reading has exactly the same trap
with open("data.txt", encoding="utf-8") as f:
text = f.read()
Always pass encoding= to open(). Relying on the platform default is the single most portable-code bug in Python — it passes every test on the author's machine and fails on the first Windows user's.
The errors= argument, and why to avoid it
text = "price: ₹100"
text.encode("ascii", errors="replace") # b'price: ?100'
text.encode("ascii", errors="ignore") # b'price: 100'
text.encode("ascii", errors="xmlcharrefreplace") # b'price: ₹100'
text.encode("ascii", errors="backslashreplace") # b'price: \\u20b9100'
These are escape hatches, not fixes. errors='ignore' deletes data silently, and errors='replace' substitutes ? — so a currency amount becomes ?100 and nobody notices until someone reads the output. Use them only when lossy output is genuinely acceptable, such as a log line that must never crash a process.
If you are reaching for errors=, ask first whether the real fix is to write UTF-8 instead. Almost always it is.
Diagnosing systematically
- Read the codec name in the message.
utf-8means something unusual such as a lone surrogate;asciiorcp1252means the target is too narrow. - Check what the default encoding actually is:
python -c "import sys; print(sys.stdout.encoding, sys.getdefaultencoding())". - If it is a console problem, reconfigure stdout or set
PYTHONIOENCODING. - If it is a file problem, add
encoding="utf-8"to everyopen()call — reads and writes. - If it is a subprocess or pipe, pass
encoding="utf-8"tosubprocess.run()as well. - Only then consider
errors=, and preferbackslashreplaceso the lost character stays visible.
import subprocess
# subprocess pipes have the same platform-default trap
result = subprocess.run(["cmd"], capture_output=True, text=True,
encoding="utf-8", errors="backslashreplace")
Related messages worth knowing
- UnicodeDecodeError: 'utf-8' codec can't decode byte — the mirror image — bytes to text, usually a binary file or wrong encoding.
- ValueError — the parent class of both Unicode errors.
- AttributeError — what you get calling encode() on bytes instead of str.
🇮🇳 Hindi में समझें
UnicodeEncodeError: 'utf-8' codec can't encode character ka matlab hai aapne text ko bytes me badalne ki koshish ki aur target codec wo character represent nahi kar sakta. Direction dhyan se dekho: encode matlab text → bytes, jo UnicodeDecodeError ka ulta hai. Ek confusing baat: UTF-8 har Unicode character encode kar sakta hai. Isliye asli 'utf-8' codec can't encode error rare hai — aam taur par message me ascii, cp1252 ya latin-1 likha hota hai, matlab target encoding bahut narrow hai. Sabse pehle message me codec ka naam padho. Sabse common case Windows console hai, jo purane code page (cp1252) par default karta hai — file sahi hoti hai par print fail hota hai. Fix: sys.stdout.reconfigure(encoding='utf-8') (Python 3.7+), ya environment me PYTHONIOENCODING=utf-8 set karo. Doosra common case file likhna hai: open() ka default encoding platform par depend karta hai, isliye macOS ya Linux par chalne wala code Windows par fail hota hai. Hamesha open() me encoding='utf-8' do — padhne aur likhne dono me. Ye Python ka sabse common portability bug hai: author ki machine par sab test pass hote hain aur pehle Windows user par fail hota hai. errors='replace' ya errors='ignore' fix nahi, escape hatch hain — ignore data chupchaap mita deta hai aur replace ? daal deta hai, to ₹100 ban jaata hai ?100. Pehle ye pucho ki asli fix UTF-8 likhna to nahi.