{"record":{"id":"b8695c71616e21b4","repo":"Textualize/textual","slug":"self-name-must-be-a-str","errorCode":null,"errorMessage":"{self.name} must be a str","messagePattern":"(.+?) must be a str","errorType":"validation","errorClass":"StyleTypeError","httpStatus":null,"severity":"error","filePath":"src/textual/css/_style_properties.py","lineNumber":932,"sourceCode":"        return obj.get_rule(self.name, \"\")  # type: ignore[return-value]\n\n    def __set__(self, obj: StylesBase, name: str | None):\n        \"\"\"Set the name property.\n\n        Args:\n            obj: The ``Styles`` object.\n            name: The name to set the property to.\n\n        Raises:\n            StyleTypeError: If the value is not a ``str``.\n        \"\"\"\n        _rich_traceback_omit = True\n        if name is None:\n            if obj.clear_rule(self.name):\n                obj.refresh(layout=True)\n        else:\n            if not isinstance(name, str):\n                raise StyleTypeError(f\"{self.name} must be a str\")\n            if obj.set_rule(self.name, name):\n                obj.refresh(layout=True)\n\n\nclass NameListProperty:\n    def __set_name__(self, owner: StylesBase, name: str) -> None:\n        self.name = name\n\n    def __get__(\n        self, obj: StylesBase, objtype: type[StylesBase] | None = None\n    ) -> tuple[str, ...]:\n        return obj.get_rule(self.name, ())  # type: ignore[return-value]\n\n    def __set__(self, obj: StylesBase, names: str | tuple[str] | None = None):\n        _rich_traceback_omit = True\n        if names is None:\n            if obj.clear_rule(self.name):\n                obj.refresh(layout=True)","sourceCodeStart":914,"sourceCodeEnd":950,"githubUrl":"https://github.com/Textualize/textual/blob/06dbeef4bb70fb718236aa418ed658ef4667a126/src/textual/css/_style_properties.py#L914-L950","documentation":"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.","triggerScenarios":"`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.","commonSituations":"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.","solutions":["Coerce the value to str before assignment, or pass None to clear the rule","Validate external config values with a type check before applying them to styles"],"exampleFix":"# before\nstyles.link_id = 42\n# after\nstyles.link_id = str(42)  # or None to clear","handlingStrategy":"type-guard","validationCode":"if name is None or isinstance(name, str):\n    styles.link_id = name","typeGuard":"def is_style_name(v) -> bool:\n    return v is None or isinstance(v, str)","tryCatchPattern":null,"preventionTips":["Normalize external style values to str or None before applying"],"tags":["textual","css","type-error","style-property"],"backgroundTag":"type-validation-failed","analyzedSha":"06dbeef4bb70fb718236aa418ed658ef4667a126","analyzedAt":"2026-08-27T02:36:57.214Z","schemaVersion":2},"datasetVersion":"2026-08-27T03:17:27.898Z"}