Textualize/textual · error · SelectionError

Expected 2 or 3 values, got {len(selection)}

Error message

Expected 2 or 3 values, got {len(selection)}

What it means

Raised by SelectionList._make_selection when a tuple passed as an option has neither 2 elements (prompt, value) nor 3 elements (prompt, value, initial_state). Tuples of any other length cannot be interpreted as a Selection.

Source

Thrown at src/textual/widgets/_selection_list.py:472

        Args:
            selection: The selection data.

        Returns:
            An instance of a `Selection`.

        Raises:
            SelectionError: If the selection was badly-formed.
        """

        # If we've been given a tuple of some sort, turn that into a proper
        # Selection.
        if isinstance(selection, tuple):
            if len(selection) == 2:
                selection = cast(
                    "tuple[ContentText, SelectionType, bool]", (*selection, False)
                )
            elif len(selection) != 3:
                raise SelectionError(f"Expected 2 or 3 values, got {len(selection)}")
            selection = Selection[SelectionType](*selection)

        # At this point we should have a proper selection.
        assert isinstance(selection, Selection)

        # If the initial state for this is that it's selected, add it to the
        # selected collection.
        if selection.initial_state:
            self._select(selection.value)

        return selection

    def _toggle_highlighted_selection(self) -> None:
        """Toggle the state of the highlighted selection.

        If nothing is selected in the list this is a non-operation.
        """
        if self.highlighted is not None:

View on GitHub (pinned to 06dbeef4bb)

Solutions

  1. Use exactly (prompt, value) or (prompt, value, initial_state: bool).
  2. Use Selection(prompt, value, initial_state) objects explicitly for clarity.
  3. Slice extra fields out of data rows before passing.

Example fix

# before
SelectionList([(row[0], row[1], row[2], row[3]) for row in rows])
# after
SelectionList([(row[0], row[1], bool(row[2])) for row in rows])
Defensive patterns

Strategy: type-guard

Validate before calling

items = [tuple(t[:3]) if len(t) > 3 else t for t in items]  # or validate len(t) in (2,3)

Type guard

def is_valid_selection_tuple(t) -> bool: return isinstance(t, tuple) and len(t) in (2, 3)

Prevention

When it happens

Trigger: SelectionList([("a", 1, True, "extra")]) or SelectionList([("only-prompt",)]), or add_options with malformed tuples.

Common situations: Building selection tuples dynamically and appending extra metadata, unpacking rows from a database with extra columns, or forgetting the initial-state boolean.

Related errors


AI-assisted analysis of Textualize/textual@06dbeef4bb (2026-08-27). Data as JSON: /api/errors/d36d40aa1500eb7d. Report an issue: GitHub.