Textualize/rich · warning · TypeError

slices with step!=1 are not supported

Error message

slices with step!=1 are not supported

What it means

Text.__getitem__ supports int indexing and slicing, but only slices with step == 1 (it uses divide() to keep style spans aligned with the cut). Slices with step != 1 (e.g. t[::2], t[::-1]) would require non-contiguous span handling, which rich deliberately did not implement, so it raises TypeError('slices with step!=1 are not supported').

Source

Thrown at rich/text.py:222

                    _Span(0, 1, style)
                    for start, end, style in self._spans
                    if end > offset >= start
                ],
                end="",
            )
            return text

        if isinstance(slice, int):
            return get_text_at(slice)
        else:
            start, stop, step = slice.indices(len(self.plain))
            if step == 1:
                lines = self.divide([start, stop])
                return lines[1]
            else:
                # This would be a bit of work to implement efficiently
                # For now, its not required
                raise TypeError("slices with step!=1 are not supported")

    @property
    def cell_len(self) -> int:
        """Get the number of cells required to render this text."""
        return cell_len(self.plain)

    @property
    def markup(self) -> str:
        """Get console markup to render this Text.

        Returns:
            str: A string potentially creating markup tags.
        """
        from .markup import escape

        output: List[str] = []

        plain = self.plain

View on GitHub (pinned to 9d8f9a372c)

Solutions

  1. Operate on the plain string and rebuild: Text(text.plain[::2]) — accepting that styles are lost.
  2. For step != 1 with styles preserved, build manually: Text('').join(text.plain[i] and text[i] ... ) — or concatenate per-character slices text[i:i+1] in a loop.
  3. Restructure to use contiguous sub-slices only (step 1), e.g. reverse via ''.join(reversed(...)) on .plain if styling is unimportant.

Example fix

# before
out = text[::-1]  # TypeError: slices with step!=1

# after
out = Text(text.plain[::-1])  # styles dropped, works
Defensive patterns

Strategy: fallback

Validate before calling

def safe_slice(text, start=None, stop=None, step=1):
    if step == 1:
        return text[start:stop]
    return Text(text.plain[start:stop:step])  # styles lost

Type guard

def is_contiguous_slice(s: slice) -> bool:
    return s.step is None or s.step == 1

Try / catch

try:
    part = text[::2]
except TypeError:
    part = Text(text.plain[::2])

Prevention

When it happens

Trigger: text[::2], text[1:10:2], text[::-1] on a Text instance — including negative step (reversal) which always has step != 1. Slices like t[2:8] or t[:5] work fine; slice.indices() is used so any step other than 1, positive or negative, trips it.

Common situations: Porting plain-str slicing code (s[::-1] for reversal, s[::2] for every-other-char) to Text; truncation/abbreviation helpers generalized from strings; list-comprehension style tricks applied to styled text.

Related errors


AI-assisted analysis of Textualize/rich@9d8f9a372c (2026-08-15). Data as JSON: /api/errors/3674cd2afd08c867. Report an issue: GitHub.