Textualize/rich · error · ColorParseError

color components must be <= 255 in {original_color!r}

Error message

color components must be <= 255 in {original_color!r}

What it means

After splitting an rgb(...) color into three integers, rich verifies each channel is <= 255 and raises ColorParseError("color components must be <= 255 in ...") otherwise. The regex only requires digit groups, so out-of-range values like 300 parse as integers but fail this semantic check. Negative values cannot occur (the regex has no minus sign), so this is purely an upper-bound failure.

Source

Thrown at rich/color.py:479

            number = int(color_8)
            if number > 255:
                raise ColorParseError(f"color number must be <= 255 in {color!r}")
            return cls(
                color,
                type=(ColorType.STANDARD if number < 16 else ColorType.EIGHT_BIT),
                number=number,
            )

        else:  #  color_rgb:
            components = color_rgb.split(",")
            if len(components) != 3:
                raise ColorParseError(
                    f"expected three components in {original_color!r}"
                )
            red, green, blue = components
            triplet = ColorTriplet(int(red), int(green), int(blue))
            if not all(component <= 255 for component in triplet):
                raise ColorParseError(
                    f"color components must be <= 255 in {original_color!r}"
                )
            return cls(color, ColorType.TRUECOLOR, triplet=triplet)

    @lru_cache(maxsize=1024)
    def get_ansi_codes(self, foreground: bool = True) -> Tuple[str, ...]:
        """Get the ANSI escape codes for this color."""
        _type = self.type
        if _type == ColorType.DEFAULT:
            return ("39" if foreground else "49",)

        elif _type == ColorType.WINDOWS:
            number = self.number
            assert number is not None
            fore, back = (30, 40) if number < 8 else (82, 92)
            return (str(fore + number if foreground else back + number),)

        elif _type == ColorType.STANDARD:

View on GitHub (pinned to 9d8f9a372c)

Solutions

  1. Clamp each channel with min(255, max(0, int(x))) before formatting the rgb string
  2. Fix the scaling factor (e.g. use int(pct * 255 / 100) for percentages)
  3. Use round() after float scaling to avoid overshoot

Example fix

// before (Python)
Color.parse(f"rgb({level*3},{0},{0})")  # level=100 -> 300 -> error
// after
r = min(255, level * 3)
Color.parse(f"rgb({r},0,0)")
Defensive patterns

Strategy: validation

Validate before calling

r, g, b = (min(255, max(0, int(c))) for c in (r, g, b))
color_str = f"rgb({r},{g},{b})"

Type guard

def is_in_range_channel(v: int) -> bool:
    return isinstance(v, int) and 0 <= v <= 255

Prevention

When it happens

Trigger: Color.parse("rgb(300,0,0)"); scaling data to color channels with math that can exceed 255 (e.g. heat = value * 3); passing hex-derived values computed with a wrong multiplier.

Common situations: Data-visualization code mapping magnitudes to RGB without clamping; unit mistakes (percent 0-100 multiplied by 255 instead of 2.55); copy-pasted channel values above 255 from float calculations rounded up.

Related errors


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