UnicodeEncodeError quando stampi una risposta LLM in Python: 3 soluzioni
print(reply) va in crash con cirillico o emoji? Scopri perché Python fallisce con output rediretto o una code page legacy, e risolvilo con la modalità UTF-8, reconfigure o encoding=.

In questa pagina
La tua richiesta è andata a buon fine, il modello ha risposto, e poi Python è morto su print(reply). L'API non c'entra. La risposta è corretta; il posto in cui la stampi non riesce a rappresentare alcuni dei suoi caratteri. La soluzione più rapida è attivare la modalità UTF-8 con PYTHONUTF8=1. Se preferisci tenerlo dentro lo script, chiama sys. in cima, e quando salvi una risposta su file, passa encoding="utf-8" a open().
Come si presenta l'errore#
Supponi di fare una domanda a un modello in russo e di stampare la risposta. Questo è lo script completo, che usa la semplice chiamata requests della nostra guida alla prima richiesta:
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)Quando stdout è rediretto su un file o una pipe, oppure Python è stato avviato con una code page legacy per i suoi stream, l'ultima riga termina così:
UnicodeEncodeError: 'charmap' codec can't encode characters in position 0-5: character maps to <undefined>Il nome del codec nel tuo messaggio dipende dalla codifica dello stream (per una code page di Windows di solito è charmap, per ascii è ascii), e le posizioni dipendono dalla risposta. La forma è sempre la stessa: il traceback punta a print, non alla richiesta.

Perché succede? print converte il testo in byte usando la codifica di sys.stdout. Se quella codifica è una code page legacy, qualsiasi carattere al di fuori di essa, come il cirillico in una code page occidentale, un'emoji, a volte un trattino tipografico, non ha un byte in cui trasformarsi. Python solleva un'eccezione invece di indovinare.
Si manifesta in tre situazioni:
- stdout è rediretto o in pipe (
python app.,py > out. txt | another program), oppure lo script viene eseguito da uno scheduler, da una CI o da un editor in cui stdout non è una console; PYTHONLEGACYWINDOWSSTDIOè impostata, oppure lo stream riceve comunque una codifica ristretta;- scrivi la risposta su un file con
open(path, "w")e senzaencoding=.
Quale Python? Tutto quanto segue riguarda Python 3.7–3.14, dove la codifica degli stream e dei file deriva dal sistema. Secondo il PEP 686 (stato Final, https://peps.python.org/pep-0686/, verificato il 5 novembre 2026), la modalità UTF-8 è attiva per impostazione predefinita da Python 3.15, quindi open() e stdio usano già UTF-8 lì, a meno che qualcuno non l'abbia disattivata con PYTHONUTF8=0 o -X utf8=0. Verifica con python --version.
Controlla quale codifica hai davvero#
Prima di cambiare qualcosa, guarda cosa ha scelto Python. Bastano dieci secondi.
Provalo tu stessoProvalo: secondo Python, qual è la codifica del tuo stdout?Mostra risposta
Esegui python - nella stessa finestra in cui lo script fallisce. In una console interattiva di solito stampa utf-8, quindi da solo dimostra poco. Eseguilo di nuovo con > check.txt in fondo e apri il file: l'output rediretto è ciò che più spesso dà un nome cp… o ascii, ed è il tuo colpevole. Se tutto dice utf-8, guarda un file su cui scrivi.
Vuoi vedere il crash senza aspettare una giornata storta? Su macOS o Linux, forza una codifica ristretta per una singola esecuzione:
PYTHONIOENCODING=ascii python -c "print('Привет')"Fallisce con un messaggio del codec ascii, della stessa famiglia dell'errore qui sopra. Su Windows la variabile viene ignorata per una console interattiva, ma funziona quando l'output è rediretto: in cmd esegui set PYTHONIOENCODING=ascii, poi python - (in PowerShell: $env:PYTHONIOENCODING = "ascii").
Soluzione 1: attiva la modalità UTF-8#
Python ha una modalità che rende UTF-8 la codifica predefinita per il testo. Secondo la documentazione di Python (pagina della riga di comando, verificata il 5 novembre 2026), PYTHONUTF8=1 la attiva e -X utf8 fa lo stesso; entrambe esistono da Python 3.7. Un'avvertenza dalla stessa pagina: qualsiasi altro valore non vuoto di PYTHONUTF8 causa un errore all'avvio, quindi usa esattamente 1 (o 0 per disattivarla). Su 3.15 ti serve solo per attivare esplicitamente la modalità su interpreti più vecchi; se lì è già attiva, cerca PYTHONUTF8=0 nel tuo ambiente.
Attiva la modalità UTF-8 per una singola esecuzione
cmd
set PYTHONUTF8=1
python app.pyPowerShell
$env:PYTHONUTF8 = "1"
python app.pymacOS / Linux
PYTHONUTF8=1 python app.pyNessuna modifica al codice, e copre la console, i redirect e i file in quell'esecuzione. Se non vuoi impostare una variabile ogni volta, python - dà lo stesso risultato dalla riga di comando.
C'è anche PYTHONIOENCODING=utf-, che sovrascrive solo la codifica di stdin, stdout e stderr. Leggi la sua voce nella documentazione prima di affidarti a essa su Windows: da Python 3.6 viene ignorata per un buffer di console interattiva a meno che PYTHONLEGACYWINDOWSSTDIO non sia impostata. File e pipe rediretti non sono interessati da quell'eccezione. Quindi può risolvere python app. e comunque non fare nulla nella finestra della console. Per stderr l'error handler è sempre backslashreplace.
Soluzione 2: riconfigura stdout dentro lo script#
Se non puoi controllare come le persone avviano lo script, cambia lo stream stesso in cima al file:
import sys
sys.stdout.reconfigure(encoding="utf-8")
sys.stderr.reconfigure(encoding="utf-8")
print(reply)reconfigure è documentato per io.TextIOWrapper (aggiunto in 3.7). Quando passi encoding e ometti errors, l'handler è strict, quindi un carattere che non rientra solleva comunque un'eccezione; nel caso comune di UTF-8 non resta nulla fuori. Due dettagli dalla documentazione: la codifica non può essere cambiata una volta che sono stati letti dati dallo stream (può esserlo dopo una scrittura), e encoding="locale" è supportato da 3.11.
Ti serve che lo script non vada mai in crash, nemmeno su un terminale che davvero non riesce a mostrare il testo? Aggiungi errors="replace". I caratteri sconosciuti appaiono allora come ? invece di fermare l'esecuzione. Questo nasconde il problema invece di risolverlo, quindi tienilo per i log.
Soluzione 3: dai ai file una codifica esplicita#
Salvare una risposta è lo stesso errore, solo più silenzioso nel codice:
# 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)Usa lo stesso encoding="utf-8" quando rileggi il file, altrimenti il testo può rompersi in ingresso.

Quale soluzione dovresti usare?#
Scegli il tuo caso
Scegli il tuo caso
Scegli un'opzione per vedere la risposta
Eseguo il mio script in un terminale
Imposta PYTHONUTF8=1 una volta nel tuo ambiente, oppure avvia con python -. Nulla nel codice cambia.
Distribuisco lo script ad altre persone
Metti sys. in cima, così funziona comunque lo avviino.
Il crash è su un file, non sullo schermo
Aggiungi encoding="utf-8" a open(), sia in scrittura che in lettura.
Puoi combinarle. Uno script che stampa e salva risposte ha bisogno della Soluzione 2 o della Soluzione 1 per lo schermo e della Soluzione 3 per il file.
Se fallisce ancora#
- L'errore si è spostato su un'altra riga. Allora la chiamata che fallisce è un'altra
printowrite; la soluzione deve essere applicata prima che venga eseguita, quindi mettireconfigurein cima al file. - L'errore menziona
PYTHONUTF8. La variabile ha un valore diverso da1o0. Rimuovila e impostala di nuovo. - Nessun crash, ma vedi quadrati o
?nella console. Python ha scritto UTF-8 valido; il font o la code page della console non riescono a mostrarlo. Redirigi su un file e aprilo in un editor per confermare che la risposta sia intatta. - L'errore è un
JSONDecodeError, non unUnicodeEncodeError. Problema diverso: vedi come estrarre JSON da una risposta del modello.
Il codice della richiesta qui sopra è la semplice chiamata requests; la documentazione di CheapTokens mostra la stessa chiamata per l'SDK OpenAI. Un altro modello funziona con la stessa soluzione: sostituisci il campo model con zai- (fino a 8.192 token di output per risposta, 390K di contesto). L'errore di codifica non ha nulla a che fare con il modello, solo con dove va il testo.



