Textualize/textual · error · ValueError
The document line index {line_index!r} is out of bounds. The
Error message
The document line index {line_index!r} is out of bounds. The document contains {len(wrap_offsets)!r} lines. What it means
WrappedDocument.get_offsets raises ValueError when line_index is negative or >= the number of wrapped lines. Each entry in _wrap_offsets corresponds to one document line, so the index space is document line indices.
Source
Thrown at src/textual/document/_wrapped_document.py:439
return [line.plain for line in wrapped_lines]
def get_offsets(self, line_index: int) -> list[int]:
"""Given a line index, get the offsets within that line where wrapping
should occur for the current document.
Args:
line_index: The index of the line within the document.
Raises:
ValueError: When `line_index` is out of bounds.
Returns:
The offsets within the line where wrapping should occur.
"""
wrap_offsets = self._wrap_offsets
out_of_bounds = line_index < 0 or line_index >= len(wrap_offsets)
if out_of_bounds:
raise ValueError(
f"The document line index {line_index!r} is out of bounds. "
f"The document contains {len(wrap_offsets)!r} lines."
)
return wrap_offsets[line_index]
def get_tab_widths(self, line_index: int) -> list[int]:
"""Return a list of the tab widths for the given line index.
Args:
line_index: The index of the line in the document.
Returns:
An ordered list of the expanded width of the tabs in the line.
"""
return self._tab_width_cache[line_index]
View on GitHub (pinned to 06dbeef4bb)
Solutions
- Clamp: max(0, min(line_index, wrapped_doc.line_count - 1))
- Recompute line indices from the wrapped document after any text change
- Guard navigation helpers to no-op at the first/last line
Example fix
# before
offsets = wrapped.get_offsets(line_index) # may be == line_count
# after
if 0 <= line_index < wrapped.line_count:
offsets = wrapped.get_offsets(line_index) Defensive patterns
Strategy: validation
Validate before calling
def safe_offsets(wrapped, line_index: int):
if not 0 <= line_index < wrapped.line_count:
return []
return wrapped.get_offsets(line_index) Type guard
def valid_line(wrapped, line_index: int) -> bool:
return 0 <= line_index < wrapped.line_count Try / catch
try:
offsets = wrapped.get_offsets(line_index)
except ValueError:
offsets = [] # treat as no wrap points Prevention
- Recompute line indices after any document edit
- Clamp line_index to [0, line_count - 1]
- Guard first/last-line navigation helpers
When it happens
Trigger: Calling get_offsets(n) after the document shrank (line deleted) while holding a stale line index; or off-by-one logic like get_offsets(line_count) instead of line_count - 1. Called transitively via is_start_of_wrapped_line, get_location_above/below, etc.
Common situations: Custom TextArea renderers/navigation code caching line indices across edits; widgets computing 'line above/below' at the first/last line without bounds checks.
Related errors
- Index {index!r} does not correspond to a location in the doc
- Cannot add an edit to history before it has been performed u
- Can't animate attribute {attribute!r} on {obj!r}; attribute
- Don't know how to animate {value!r}; Can only animate <int>,
- Can't encode {datum!r}
AI-assisted analysis of Textualize/textual@06dbeef4bb (2026-08-27).
Data as JSON: /api/errors/c34f21531406ea76.
Report an issue: GitHub.