Back to blog

TroubleshootingGuide

UnicodeEncodeError when printing an LLM reply in Python: 3 fixes

print(reply) crashes on Cyrillic or emoji? See why Python fails with redirected output or a legacy code page, and fix it with UTF-8 mode, reconfigure or encoding=.

By CheapTokens TeamPublished 6 min read

UnicodeEncodeError on print(reply) and the UTF-8 fix, drawn as an error card
On this page
  1. What the error looks like
  2. Check which encoding you actually have
  3. Fix 1: switch on UTF-8 mode
  4. Fix 2: reconfigure stdout inside the script
  5. Fix 3: give files an explicit encoding
  6. Which fix should you use?
  7. If it still fails

Your request went through, the model answered, and then Python died on print(reply). The API isn't at fault. The reply is fine; the place you print it to can't represent some of its characters. The quickest fix is to turn on UTF-8 mode with PYTHONUTF8=1. If you'd rather keep it inside the script, call sys.stdout.reconfigure(encoding="utf-8") at the top, and when you save a reply to a file, pass encoding="utf-8" to open().

What the error looks like#

Say you ask a model a question in Russian and print the answer. This is the whole script, using the plain requests call from our first-request guide:

python
import os, requests

r = requests.post(
    "https://api.cheaptokens.dev/v1/chat/completions",
    headers={"Authorization": f"Bearer {os.environ['CHEAPTOKENS_API_KEY']}"},
    json={
        "model": "deepseek-ai/DeepSeek-V4-Flash-0731",
        "messages": [{"role": "user", "content": "Ответь одним предложением: что такое токен?"}],
        "max_tokens": 200,
    },
)
reply = r.json()["choices"][0]["message"]["content"]
print(reply)

When stdout is redirected to a file or pipe, or Python was started with a legacy code page for its streams, the last line ends like this:

text
UnicodeEncodeError: 'charmap' codec can't encode characters in position 0-5: character maps to <undefined>

The codec name in your message depends on the stream's encoding (for a Windows code page it is usually charmap, for ascii it is ascii), and the positions depend on the reply. The shape is always the same: the traceback points at print, not at the request.

A UnicodeEncodeError traceback pointing at print(reply)
Typical shape of the error: it is raised by print, after the API call has already succeeded

Why does it happen? print converts the text to bytes using the encoding of sys.stdout. If that encoding is a legacy code page, any character outside it, such as Cyrillic in a Western code page, an emoji, sometimes a typographic dash, has no byte to turn into. Python raises instead of guessing.

It shows up in three situations:

  • stdout is redirected or piped (python app.py > out.txt, | another program), or the script runs from a scheduler, CI or an editor where stdout isn't a console;
  • PYTHONLEGACYWINDOWSSTDIO is set, or the stream otherwise gets a narrow encoding;
  • you write the reply to a file with open(path, "w") and no encoding=.

Which Python? Everything below is about Python 3.7–3.14, where the stream and file encoding come from the system. Per PEP 686 (status Final, https://peps.python.org/pep-0686/, checked 5 November 2026), UTF-8 mode is on by default from Python 3.15, so open() and stdio already use UTF-8 there unless someone turned it off with PYTHONUTF8=0 or -X utf8=0. Check with python --version.

Check which encoding you actually have#

Before you change anything, look at what Python picked. It takes ten seconds.

Try it yourselfTry it: what does Python think your stdout encoding is?Show answer

Run python -c "import sys; print(sys.stdout.encoding)" in the same window where the script fails. In an interactive console it usually prints utf-8, so that alone proves little. Run it again with > check.txt at the end and open the file: redirected output is what more often gives a cp… name or ascii, and that is your culprit. If everything says utf-8, look at a file you write to.

Want to see the crash without waiting for a bad day? On macOS or Linux, force a narrow encoding for one run:

bash
PYTHONIOENCODING=ascii python -c "print('Привет')"

That fails with an ascii codec message, the same family as the error above. On Windows the variable is ignored for an interactive console, but it works when output is redirected: in cmd run set PYTHONIOENCODING=ascii, then python -c "print('Привет')" > out.txt (in PowerShell: $env:PYTHONIOENCODING = "ascii").

Fix 1: switch on UTF-8 mode#

Python has a mode that makes UTF-8 the default for text. Per the Python docs (command-line page, checked 5 November 2026), PYTHONUTF8=1 turns it on and -X utf8 does the same; both exist since Python 3.7. One catch from the same page: any other non-empty value of PYTHONUTF8 causes an error at startup, so use exactly 1 (or 0 to switch it off). On 3.15 you only need this to enable the mode explicitly on older interpreters; if it's on there already, look for PYTHONUTF8=0 in your environment.

Turn on UTF-8 mode for one run

cmd

bat
set PYTHONUTF8=1
python app.py

PowerShell

powershell
$env:PYTHONUTF8 = "1"
python app.py

macOS / Linux

bash
PYTHONUTF8=1 python app.py

No code changes, and it covers the console, redirects and files in that run. If you don't want to set a variable each time, python -X utf8 app.py gives the same result from the command line.

There is also PYTHONIOENCODING=utf-8, which overrides the encoding of stdin, stdout and stderr only. Read its docs entry before you rely on it on Windows: since Python 3.6 it is ignored for an interactive console buffer unless PYTHONLEGACYWINDOWSSTDIO is set. Redirected files and pipes are not affected by that exception. So it can fix python app.py > out.txt and still do nothing in the console window. For stderr the error handler is always backslashreplace.

Fix 2: reconfigure stdout inside the script#

If you can't control how people start the script, change the stream itself at the very top:

python
import sys

sys.stdout.reconfigure(encoding="utf-8")
sys.stderr.reconfigure(encoding="utf-8")

print(reply)

reconfigure is documented for io.TextIOWrapper (added in 3.7). When you pass encoding and leave errors out, the handler is strict, so a character that doesn't fit still raises; for the common case of UTF-8 nothing is left over. Two details from the docs: the encoding can't be changed once data has been read from the stream (it can after a write), and encoding="locale" is supported since 3.11.

Need the script to never crash, even on a terminal that really can't show the text? Add errors="replace". Unknown characters then appear as ? instead of stopping the run. That hides the problem rather than fixing it, so keep it for logs.

Fix 3: give files an explicit encoding#

Saving a reply is the same failure, only quieter in the code:

python
# before: on Python up to 3.14 this uses the system's default encoding
with open("reply.txt", "w") as f:
    f.write(reply)

# after: the file is UTF-8 on every machine
with open("reply.txt", "w", encoding="utf-8") as f:
    f.write(reply)

Use the same encoding="utf-8" when you read the file back, otherwise the text can break on the way in instead.

Before: print(reply) raises UnicodeEncodeError. After: the same line prints the full reply
The same print line, before and after UTF-8 mode

Which fix should you use?#

Pick your case

Pick your case

I run my own script in a terminal

Set PYTHONUTF8=1 once in your environment, or start with python -X utf8 app.py. Nothing in the code changes.

I ship the script to other people

Put sys.stdout.reconfigure(encoding="utf-8") at the top, so it works however they launch it.

The crash is on a file, not on screen

Add encoding="utf-8" to open(), for writing and reading.

You can combine them. A script that prints and saves replies needs Fix 2 or Fix 1 for the screen and Fix 3 for the file.

If it still fails#

  • Error moved to a different line. Then the failing call is another print or write; the fix has to apply before it runs, so put reconfigure at the very top.
  • Error mentions PYTHONUTF8. The variable has a value other than 1 or 0. Remove it and set it again.
  • No crash, but you see squares or ? in the console. Python wrote valid UTF-8; the console font or code page can't display it. Redirect to a file and open the file in an editor to confirm the reply is intact.
  • The error is a JSONDecodeError, not UnicodeEncodeError. Different problem: see how to extract JSON from a model reply.

The request code above is the plain requests call; the CheapTokens docs show the same call for the OpenAI SDK. Another model works with the same fix: swap the model field for zai-org/GLM-5.3-Flash (up to 8,192 output tokens per answer, 390K context). The encoding error has nothing to do with the model, only with where the text goes.