Textualize/textual · error · IndexError
No line no. {line} in the tree
Error message
No line no. {line} in the tree What it means
IndexError from Tree.move_cursor_to_line(): the requested line number doesn't exist in the flattened list of visible tree lines (self._tree_lines). Only expanded, visible nodes occupy lines.
Source
Thrown at src/textual/widgets/_tree.py:994
animate=animate and abs(self.cursor_line - previous_cursor_line) > 1,
)
def move_cursor_to_line(self, line: int, animate=False) -> None:
"""Move the cursor to the given line.
Args:
line: The line number (negative indexes are offsets from the last line).
animate: Enable scrolling animation.
Raises:
IndexError: If the line doesn't exist.
"""
if self.cursor_line == line:
return
try:
node = self._tree_lines[line].node
except IndexError:
raise IndexError(f"No line no. {line} in the tree")
self.move_cursor(node, animate=animate)
def select_node(self, node: TreeNode[TreeDataType] | None) -> None:
"""Move the cursor to the given node and select it, or reset cursor.
Args:
node: A tree node to move the cursor to and select, or None to reset cursor.
"""
self.move_cursor(node)
if node is not None:
self.post_message(Tree.NodeSelected(node))
def unselect(self) -> None:
"""Hide and reset the cursor."""
self.set_reactive(Tree.cursor_line, -1)
self._invalidate()
@on(NodeSelected)View on GitHub (pinned to 06dbeef4bb)
Solutions
- Clamp the line: `tree.move_cursor_to_line(min(line, len(tree._tree_lines) - 1))`.
- Move by node instead: `tree.move_cursor(tree.get_node_by_id(node_id))` (guard UnknownNodeID).
- Re-check line count after structural changes/collapses before moving.
Example fix
# before
tree.move_cursor_to_line(saved_line)
# after
line = min(saved_line, len(tree._tree_lines) - 1)
if line >= 0:
tree.move_cursor_to_line(line) Defensive patterns
Strategy: validation
Validate before calling
if 0 <= line < len(tree._tree_lines):
tree.move_cursor_to_line(line) Try / catch
try:
tree.move_cursor_to_line(line)
except IndexError:
pass Prevention
- Prefer move_cursor(node) over line numbers
- Recompute line targets after collapse/remove operations
When it happens
Trigger: Calling `tree.move_cursor_to_line(n)` where n >= len(tree._tree_lines) or n < 0 after negation — common when nodes were collapsed, removed, or the tree was rebuilt since the line count was captured.
Common situations: Using a saved cursor line after `tree.clear()`; computing a target line from total node count instead of visible line count after collapsing branches.
Related errors
- Row index {row_index!r} is not valid.
- Column index {column_index!r} is not valid.
- There is no option with an index of {index}
- Unable to remove; there is no option at index {index}
- Unable to add a node both before and after a node
AI-assisted analysis of Textualize/textual@06dbeef4bb (2026-08-27).
Data as JSON: /api/errors/f60817f6616226c8.
Report an issue: GitHub.