Назад в блог

Решение проблемИнструкция

UnicodeEncodeError при print ответа модели в Python: 3 способа

print(reply) падает на кириллице или эмодзи? Почему Python ломается при перенаправлении вывода или со старой кодовой страницей и как это чинят: UTF-8 mode, reconfigure, encoding=.

Автор: CheapTokens TeamОпубликовано 5 мин чтения

UnicodeEncodeError при print(reply) и исправление через UTF-8, карточка с ошибкой
Содержание
  1. Как выглядит ошибка
  2. Сначала узнайте свою кодировку
  3. Способ 1: включить режим UTF-8
  4. Способ 2: переключить stdout внутри скрипта
  5. Способ 3: явная кодировка для файлов
  6. Какой способ выбрать
  7. Если всё равно падает

Запрос прошёл, модель ответила, а Python упал на print(reply). API тут ни при чём: ответ целый, просто то место, куда вы его печатаете, не умеет записывать часть его символов. Быстрее всего помогает режим UTF-8: PYTHONUTF8=1. Если хотите решить это внутри скрипта, поставьте в начало sys.stdout.reconfigure(encoding="utf-8"), а при записи ответа в файл передавайте в open() аргумент encoding="utf-8".

Как выглядит ошибка#

Допустим, вы задаёте модели вопрос по-русски и печатаете ответ. Весь скрипт, на простом requests из нашей статьи про первый запрос:

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)

Если вывод перенаправлен в файл или канал либо Python запущен со старой кодовой страницей для потоков, последняя строка заканчивается так:

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

Имя кодека у вас зависит от кодировки потока (для кодовой страницы Windows это обычно charmap, для ascii — ascii), а позиции от ответа. Форма всегда одна: трассировка указывает на print, а не на запрос.

Трассировка UnicodeEncodeError, указывающая на print(reply)
Типичный вид ошибки: её вызывает print, когда вызов API уже прошёл

Почему так? print превращает текст в байты кодировкой sys.stdout. Если это старая кодовая страница, символу вне её просто нет байта: кириллице в западной странице, эмодзи, иногда типографскому тире. Python не гадает и бросает исключение.

Встречается это в трёх ситуациях:

  • вывод перенаправлен или передан по каналу (python app.py > out.txt, | другая программа), либо скрипт запущен из планировщика, CI или редактора, где stdout — не консоль;
  • задана PYTHONLEGACYWINDOWSSTDIO или поток иначе получает узкую кодировку;
  • вы пишете ответ в файл через open(path, "w") без encoding=.

Какой Python? Всё ниже — про Python 3.7–3.14, где кодировку потоков и файлов берут из системы. По PEP 686 (статус Final, https://peps.python.org/pep-0686/, сверено 5 ноября 2026) с Python 3.15 режим UTF-8 включён по умолчанию, так что open() и stdio там уже в UTF-8, если его не выключили через PYTHONUTF8=0 или -X utf8=0. Версию покажет python --version.

Сначала узнайте свою кодировку#

Прежде чем что-то менять, посмотрите, что выбрал Python. Это десять секунд.

Попробуйте самиПопробуйте: какую кодировку Python считает для stdout?Показать ответ

Запустите python -c "import sys; print(sys.stdout.encoding)" в том же окне, где падает скрипт. В интерактивной консоли обычно выводится utf-8, так что одно это ещё ничего не доказывает. Запустите ещё раз с > check.txt в конце и откройте файл: именно перенаправленный вывод чаще даёт имя вида cp… или ascii, и тогда виновник найден. Если везде utf-8, смотрите на файл, в который пишете.

Хотите увидеть падение, не дожидаясь неудачного дня? На macOS или Linux принудительно задайте узкую кодировку на один запуск:

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

Ошибка будет про кодек ascii, из того же семейства, что и выше. В Windows для интерактивной консоли эта переменная игнорируется, но при перенаправлении вывода работает: в cmd выполните set PYTHONIOENCODING=ascii, затем python -c "print('Привет')" > out.txt (в PowerShell: $env:PYTHONIOENCODING = "ascii").

Способ 1: включить режим UTF-8#

У Python есть режим, где текст по умолчанию в UTF-8. По документации Python (страница командной строки, сверено 5 ноября 2026) его включает PYTHONUTF8=1, то же делает -X utf8; оба есть с Python 3.7. И одна ловушка с той же страницы: любое другое непустое значение PYTHONUTF8 вызывает ошибку при запуске, так что ставьте ровно 1 (или 0, чтобы выключить). В 3.15 явно включать режим нужно только на старых интерпретаторах; если там он уже включён, поищите в окружении PYTHONUTF8=0.

Включить режим UTF-8 на один запуск

cmd

bat
set PYTHONUTF8=1
python app.py

PowerShell

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

macOS / Linux

bash
PYTHONUTF8=1 python app.py

Код не меняется, а в этом запуске режим охватывает и консоль, и перенаправление, и файлы. Не хотите каждый раз задавать переменную? python -X utf8 app.py даёт тот же результат прямо из командной строки.

Есть ещё PYTHONIOENCODING=utf-8: она переопределяет кодировку только stdin, stdout и stderr. Прежде чем рассчитывать на неё в Windows, прочитайте её запись в документации: начиная с Python 3.6 она игнорируется для интерактивного буфера консоли, если не задана PYTHONLEGACYWINDOWSSTDIO. На перенаправленные файлы и каналы это исключение не действует. Поэтому она может вылечить python app.py > out.txt и при этом ничего не изменить в окне консоли. Для stderr обработчик ошибок всегда backslashreplace.

Способ 2: переключить stdout внутри скрипта#

Если вы не управляете тем, как скрипт запускают, поменяйте сам поток в самом начале:

python
import sys

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

print(reply)

reconfigure описан в документации для io.TextIOWrapper (появился в 3.7). Если передать encoding и не указать errors, обработчик будет strict: символ, который не помещается, всё равно вызовет ошибку, но в UTF-8 такого не остаётся. Ещё две детали из документации: кодировку нельзя менять после чтения данных из потока (после записи можно), а encoding="locale" поддерживается с 3.11.

Нужно, чтобы скрипт не падал никогда, даже в терминале, который правда не умеет показать текст? Добавьте errors="replace". Незнакомые символы превратятся в ?, и работа не остановится. Это прячет проблему, а не лечит её, так что оставьте для логов.

Способ 3: явная кодировка для файлов#

Сохранение ответа даёт ту же ошибку, только в коде она менее заметна:

python
# было: в Python до 3.14 здесь кодировка по умолчанию системы
with open("reply.txt", "w") as f:
    f.write(reply)

# стало: файл в UTF-8 на любой машине
with open("reply.txt", "w", encoding="utf-8") as f:
    f.write(reply)

Тот же encoding="utf-8" ставьте и при чтении файла, иначе текст может сломаться уже на входе.

До: print(reply) вызывает UnicodeEncodeError. После: та же строка печатает ответ целиком
Та же строка print до и после режима UTF-8

Какой способ выбрать#

Выберите свой случай

Выберите свой случай

Я запускаю свой скрипт в терминале

Один раз задайте PYTHONUTF8=1 в окружении или запускайте python -X utf8 app.py. Код не меняется.

Я отдаю скрипт другим людям

Поставьте sys.stdout.reconfigure(encoding="utf-8") в начало, и он будет работать при любом способе запуска.

Падает запись в файл, а не вывод на экран

Добавьте encoding="utf-8" в open(), и для записи, и для чтения.

Способы можно сочетать. Скрипту, который и печатает, и сохраняет ответы, нужен способ 2 или 1 для экрана и способ 3 для файла.

Если всё равно падает#

  • Ошибка переехала на другую строку. Значит, падает другой print или write; исправление должно сработать до него, поэтому reconfigure ставьте в самый верх.
  • В тексте ошибки PYTHONUTF8. У переменной значение не 1 и не 0. Уберите её и задайте заново.
  • Падения нет, но в консоли квадраты или ?. Python записал корректный UTF-8, а шрифт или кодовая страница консоли не умеют его показать. Перенаправьте вывод в файл и откройте его в редакторе: так видно, что ответ цел.
  • Ошибка — JSONDecodeError, а не UnicodeEncodeError. Это другая проблема: см. как достать JSON из ответа модели.

Код запроса выше — простой requests; в документации CheapTokens тот же вызов показан для OpenAI SDK. С другой моделью исправление работает так же: замените поле model на zai-org/GLM-5.3-Flash (до 8 192 токенов в ответе, контекст 390K). Ошибка кодировки не зависит от модели, только от того, куда уходит текст.