UnicodeEncodeError

The text has a character the target encoding has no byte for — é in ASCII, € in Latin-1, an emoji in a cp1252 console. Positions are character indexes into the str.

InheritsBaseException›Exception›ValueError›UnicodeError›UnicodeEncodeError
Type / value exceptionPython 3 (all)Live demo
UnicodeEncodeError(encodingencoding — Codec name as shown in the message, e.g. 'ascii'. Stored in e.encoding.type: str · required, objectobject — The whole str being encoded. Stored in e.object.type: str · required, startstart — Index of the first character that cannot be encoded.type: int · required, endend — Index just after the last one. end - start == 1 shows the character itself in the message; a longer range shows "characters in position S-E".type: int · required, reasonreason — Why encoding failed, e.g. 'ordinal not in range(128)'.type: str · required)
Raised by
s.encode('ascii'), print() to a cp1252 console, open(p, 'w', encoding='ascii')
Message
'ascii' codec can't encode character '\xe9' in position 3: ordinal not in range(128)
Quick fix
encode as 'utf-8', or pick an errors= handler
Watch out
a run of bad characters is reported as one range: position 0-2

Demo

Live evaluation
Encode text as ASCII — only code points 0-127 fit. Consecutive non-ASCII characters are reported together as one range.
Try:
Inputs
textstrtext to encode
Code
'hello'.encode('ascii')
Result
b'hello'

Positions count characters, not bytes: the emoji in 'ok 👍' is position 3 even though it is 4 bytes in UTF-8. The character in the message is always an escape — \xe9 for é, \u65e5 for 日, \U0001f44d for the emoji — so the message stays ASCII-safe. In Handle, xmlcharrefreplace gives é for é, ready for HTML or XML.

Constructor

NameTypeRequiredDescription
encodingstryesCodec name as shown in the message, e.g. 'ascii'. Stored in e.encoding.
objectstryesThe whole str being encoded. Stored in e.object.
startintyesIndex of the first character that cannot be encoded.
endintyesIndex just after the last one. end - start == 1 shows the character itself in the message; a longer range shows "characters in position S-E".
reasonstryesWhy encoding failed, e.g. 'ordinal not in range(128)'.

Attributes

AttributeTypeMeaning
encodingstrThe codec that failed: 'ascii', 'latin-1', 'utf-8', or 'charmap' for table codecs such as cp1252.
objectstrThe complete str that was being encoded.
startintCharacter index of the first unencodable character. object[start:end] is the offending text.
endintCharacter index just past the unencodable run.
reasonstr'ordinal not in range(128)' (ascii), 'ordinal not in range(256)' (latin-1), 'character maps to <undefined>' (charmap), 'surrogates not allowed' (utf-8).
argstupleAll five constructor arguments, in order.

Common patterns

Write text files as UTF-8
UTF-8 can encode every character except lone surrogates. Always pass encoding= so the platform default cannot bite.
with open('report.txt', 'w', encoding='utf-8') as f:
    f.write(text)
Make a console safe for any text
On a console whose encoding cannot show every character, switch stdout's error handler instead of crashing on the first emoji (Python 3.7+).
import sys
sys.stdout.reconfigure(errors='backslashreplace')
print('ok 👍')
ASCII-fold for slugs and identifiers
Decompose accented letters first, then drop the combining marks — é becomes e instead of vanishing.
import unicodedata

def ascii_fold(s):
    return unicodedata.normalize('NFKD', s).encode('ascii', 'ignore').decode('ascii')
Report the offending characters
object[start:end] is exactly the text that could not be encoded.
try:
    data = name.encode('latin-1')
except UnicodeEncodeError as e:
    bad = e.object[e.start:e.end]
    raise ValueError(f'unsupported characters {bad!r} at {e.start}') from e

Examples

1. Non-ASCII to ASCII
'café'.encode('ascii')
Returns
UnicodeEncodeError: 'ascii' codec can't encode character '\xe9' in position 3: ordinal not in range(128)
2. UTF-8 encodes everything
'café'.encode('utf-8')
Returns
b'caf\xc3\xa9'
3. A run is one error
'日本語'.encode('ascii')
Returns
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-2: ordinal not in range(128)
4. € is not in Latin-1
'€5'.encode('latin-1')
Returns
UnicodeEncodeError: 'latin-1' codec can't encode character '\u20ac' in position 0: ordinal not in range(256)
5. Inspect the attributes
try: 'naïve'.encode('ascii') except UnicodeEncodeError as e: info = (e.start, e.end, e.object[e.start:e.end], e.reason) info
Returns
(2, 3, 'ï', 'ordinal not in range(128)')
6. The Windows-console error
import io out = io.TextIOWrapper(io.BytesIO(), encoding='cp1252') out.write('ok 👍')
Returns
UnicodeEncodeError: 'charmap' codec can't encode character '\U0001f44d' in position 3: character maps to <undefined>
7. HTML-safe fallback
'café'.encode('ascii', 'xmlcharrefreplace')
Returns
b'caf&#233;'
8. Lone surrogates never encode
b'caf\xe9'.decode('utf-8', 'surrogateescape').encode('utf-8')
Returns
UnicodeEncodeError: 'utf-8' codec can't encode character '\udce9' in position 3: surrogates not allowed

Pitfalls

1. Writing a file with a narrow encoding
The encoding argument of open() applies to every write(). A single non-ASCII character anywhere in the output fails the write.
encoding='ascii'
with open('out.txt', 'w', encoding='ascii') as f:
    f.write('Zoë')
UnicodeEncodeError: 'ascii' codec can't encode character '\xeb' in position 2: ordinal not in range(128)
encoding='utf-8'
with open('out.txt', 'w', encoding='utf-8') as f:
    n = f.write('Zoë')
n
3
2. errors='ignore' deletes letters
Dropping unencodable characters turns Zoë into Zo. Normalize to NFKD first so the base letter survives.
encode(…, 'ignore')
'Zoë'.encode('ascii', 'ignore')
b'Zo'
NFKD, then ignore
import unicodedata
unicodedata.normalize('NFKD', 'Zoë').encode('ascii', 'ignore')
b'Zoe'
3. Undoing surrogateescape with the wrong handler
Text decoded with errors=surrogateescape holds lone surrogates in place of bad bytes. Encode it with the same handler to get the original bytes back.
plain encode
text = b'caf\xe9'.decode('utf-8', 'surrogateescape')
text.encode('utf-8')
UnicodeEncodeError: 'utf-8' codec can't encode character '\udce9' in position 3: surrogates not allowed
same handler
text = b'caf\xe9'.decode('utf-8', 'surrogateescape')
text.encode('utf-8', 'surrogateescape')
b'caf\xe9'

When to use

Use it
  • Catch it where text leaves your program for a restricted encoding (legacy protocol, ASCII-only header)
  • Use start/end/object to tell the user exactly which characters are not supported
  • Raise it from a custom codec (with all five arguments)
Reach for something else
  • Encoding to ASCII or Latin-1 when UTF-8 is allowed — use 'utf-8' and the error disappears
  • errors='ignore' on user-visible text — it silently removes characters
  • Catching it around print() — fix the stream encoding instead (PYTHONIOENCODING, -X utf8, reconfigure)

Notes

CPython impl
Objects/unicodeobject.c — the ASCII/Latin-1 encoder extends the error to every consecutive unencodable character before raising
Catch via
except UnicodeError (all three unicode errors) or except ValueError
Message escapes
The character is always printed as \xNN, \uNNNN or \UNNNNNNNN, never literally — so the message itself can be printed anywhere
charmap
Table-based codecs (cp1252, cp437, …) report their encoding as 'charmap' and the reason as 'character maps to <undefined>'

FAQ

Something encoded your text as ASCII, which only covers code points 0-127. If you called .encode('ascii') yourself, use 'utf-8'. If it came from open(), pass encoding='utf-8'. If it came from print() or logging, the output stream's encoding (sys.stdout.encoding) cannot represent the character; set PYTHONIOENCODING=utf-8 or run python -X utf8.