Textualize/textual · error · ValueError
Invalid UTF-8 byte: {first_byte}
Error message
Invalid UTF-8 byte: {first_byte} What it means
Raised while Textual's TextArea builds a byte-offset-to-codepoint map: the first byte of a character matches none of the UTF-8 leading-byte patterns (0xxxxxxx, 110xxxxx, 1110xxxx, 11110xxx). This means the input string's underlying bytes are not valid UTF-8, so offsets cannot be computed.
Source
Thrown at src/textual/widgets/_text_area.py:2792
while current_byte_offset < len(data):
byte_to_codepoint[current_byte_offset] = code_point_offset
first_byte = data[current_byte_offset]
# Single-byte character
if (first_byte & 0b10000000) == 0:
current_byte_offset += 1
# 2-byte character
elif (first_byte & 0b11100000) == 0b11000000:
current_byte_offset += 2
# 3-byte character
elif (first_byte & 0b11110000) == 0b11100000:
current_byte_offset += 3
# 4-byte character
elif (first_byte & 0b11111000) == 0b11110000:
current_byte_offset += 4
else:
raise ValueError(f"Invalid UTF-8 byte: {first_byte}")
code_point_offset += 1
# Mapping for the end of the string
byte_to_codepoint[current_byte_offset] = code_point_offset
return byte_to_codepoint
View on GitHub (pinned to 06dbeef4bb)
Solutions
- Sanitize text before assigning to TextArea: `text.encode('utf-8', errors='ignore').decode('utf-8')` or use `errors='replace'`.
- Decode source data explicitly with the correct codec (e.g. `data.decode('cp1252')`) instead of assuming UTF-8.
- If raw bytes must be preserved, display a hex view or repr() rather than passing them as text.
Example fix
# before
text_area.text = raw_bytes.decode('utf-8', errors='surrogateescape')
# after
text_area.text = raw_bytes.decode('utf-8', errors='replace') Defensive patterns
Strategy: validation
Validate before calling
def safe_text(raw: bytes | str) -> str:
s = raw.decode('utf-8', errors='replace') if isinstance(raw, bytes) else raw
s.encode('utf-8') # raises if still invalid
return s
text_area.text = safe_text(data) Type guard
def is_valid_utf8_text(s: str) -> bool:
try:
s.encode('utf-8')
return True
except UnicodeEncodeError:
return False Try / catch
try:
text_area.text = value
except ValueError:
text_area.text = value.encode('utf-8', 'replace').decode('utf-8') Prevention
- Always decode external bytes with an explicit codec and errors='replace'
- Never pass surrogateescape-decoded strings to Textual widgets
When it happens
Trigger: Calling TextArea/document APIs that index locations (e.g. setting text, moving the cursor, or computing offsets) with a `str` whose bytes contain invalid UTF-8 sequences — typically text decoded with error-tolerant codecs (surrogateescape) or constructed from raw bytes containing values like 0xFF/0xFE as leading bytes.
Common situations: Loading files opened in binary and decoded with errors='replace'/'surrogateescape', embedding literal bytes in source, or receiving data from sockets/subprocess output that isn't UTF-8 (e.g. latin-1 or CP1252 logs).
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- {self.name} must be a str (e.g. '10%') or a float (e.g. 0.1)
- Expected a character or hatch value here; found {character!r
- {token!r} is not a valid scalar
- {name!r} is an invalid {description}; identifiers must conta
- invalid value for display (received {new_val!r}, expected {f
AI-assisted analysis of Textualize/textual@06dbeef4bb (2026-08-27).
Data as JSON: /api/errors/e5ef5fd5f236d35a.
Report an issue: GitHub.