Textualize/textual · error · StyleTypeError

must be a str

Error message

{self.name} must be a str

What it means

The NameProperty descriptor (used for the `layer`-like name rules such as `link`-style names) requires either None (to clear the rule) or a Python str. Passing any other type (int, list, Color, etc.) raises StyleTypeError. This guards the internal rule storage which only accepts string identifiers.

Solutions

  1. Coerce the value to str before assignment, or pass None to clear the rule
  2. Validate external config values with a type check before applying them to styles

Example fix

# before
styles.link_id = 42
# after
styles.link_id = str(42)  # or None to clear
Defensive patterns

Strategy: type-guard

Validate before calling

if name is None or isinstance(name, str):
    styles.link_id = name

Type guard

def is_style_name(v) -> bool:
    return v is None or isinstance(v, str)

Prevention

When it happens

Trigger: `styles.link_id = 42`, `styles.<name-rule> = ['a','b']`, or passing a non-str variable from user input into a name-style assignment instead of a string or None.

Common situations: Programmatically building styles from unvalidated data (JSON config, DB rows) where the name field is a number; forgetting that None clears the rule while other falsy values like 0 do not.

Related errors


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

Appendix: source

Thrown at src/textual/css/_style_properties.py:932

        return obj.get_rule(self.name, "")  # type: ignore[return-value]

    def __set__(self, obj: StylesBase, name: str | None):
        """Set the name property.

        Args:
            obj: The ``Styles`` object.
            name: The name to set the property to.

        Raises:
            StyleTypeError: If the value is not a ``str``.
        """
        _rich_traceback_omit = True
        if name is None:
            if obj.clear_rule(self.name):
                obj.refresh(layout=True)
        else:
            if not isinstance(name, str):
                raise StyleTypeError(f"{self.name} must be a str")
            if obj.set_rule(self.name, name):
                obj.refresh(layout=True)


class NameListProperty:
    def __set_name__(self, owner: StylesBase, name: str) -> None:
        self.name = name

    def __get__(
        self, obj: StylesBase, objtype: type[StylesBase] | None = None
    ) -> tuple[str, ...]:
        return obj.get_rule(self.name, ())  # type: ignore[return-value]

    def __set__(self, obj: StylesBase, names: str | tuple[str] | None = None):
        _rich_traceback_omit = True
        if names is None:
            if obj.clear_rule(self.name):
                obj.refresh(layout=True)

View on GitHub (pinned to 06dbeef4bb)