{"record":{"id":"955b9a47d784ef2c","repo":"Textualize/textual","slug":"theme-theme-name-r-has-not-been-registered-call","errorCode":null,"errorMessage":"Theme {theme_name!r} has not been registered. Call 'App.register_theme' before setting the 'App.theme' attribute.","messagePattern":"Theme (.+?) has not been registered\\. Call 'App\\.register_theme' before setting the 'App\\.theme' attribute\\.","errorType":"validation","errorClass":"InvalidThemeError","httpStatus":null,"severity":"error","filePath":"src/textual/app.py","lineNumber":1500,"sourceCode":"        A dictionary mapping theme names to Theme instances.\n        \"\"\"\n        return {**self._registered_themes}\n\n    @property\n    def current_theme(self) -> Theme:\n        theme = self.get_theme(self.theme)\n        if theme is None:\n            theme = self.get_theme(\"textual-dark\")\n        assert theme is not None  # validated by _validate_theme\n        return theme\n\n    def _validate_theme(self, theme_name: str) -> str:\n        if theme_name not in self.available_themes:\n            message = (\n                f\"Theme {theme_name!r} has not been registered. \"\n                \"Call 'App.register_theme' before setting the 'App.theme' attribute.\"\n            )\n            raise InvalidThemeError(message)\n        return theme_name\n\n    def _watch_theme(self, theme_name: str) -> None:\n        \"\"\"Apply a theme to the application.\n\n        This method is called when the theme reactive attribute is set.\n        \"\"\"\n        theme = self.current_theme\n        dark = theme.dark\n        # Setting the theme adds class \"-theme-<THEME NAME>\" to the App\n        classes = {name: False for name in self.classes if name.startswith(\"-theme-\")}\n        classes[f\"-theme-{self.current_theme.name}\"] = True\n        classes[\"-dark-mode\"] = dark\n        classes[\"-light-mode\"] = not dark\n\n        self.update_classes(classes, update=False)\n\n        self._refresh_truecolor_filter(self.ansi_theme)","sourceCodeStart":1482,"sourceCodeEnd":1518,"githubUrl":"https://github.com/Textualize/textual/blob/06dbeef4bb70fb718236aa418ed658ef4667a126/src/textual/app.py#L1482-L1518","documentation":"InvalidThemeError raised by the theme reactive validator when setting App.theme to a name that is not in App.available_themes. Themes must be registered (built-in or via register_theme) before assignment.","triggerScenarios":"self.theme = \"my_custom\" without having called self.register_theme(Theme(...)); misspelling a built-in theme name like 'tokyo-night'.","commonSituations":"Adding custom themes after app startup; upgrading Textual where built-in theme names changed; setting theme from a config file value.","solutions":["Register first: self.register_theme(Theme(name=\"my_custom\", ...)) then self.theme = \"my_custom\"","Check the name exists: assert name in self.available_themes before assigning","For built-ins use exact names, e.g. \"textual-dark\", \"gruvbox\""],"exampleFix":"# before\nself.theme = \"nord\"  # not registered\n\n# after\ntheme = Theme(name=\"nord\", primary=\"#88C0D0\")\nself.register_theme(theme)\nself.theme = \"nord\"","handlingStrategy":"validation","validationCode":"if theme_name not in app.available_themes:\n    app.register_theme(Theme(name=theme_name, primary=\"#...\"))\napp.theme = theme_name","typeGuard":null,"tryCatchPattern":"try:\n    self.app.theme = name\nexcept InvalidThemeError:\n    self.log.warning(f'theme {name} missing; keeping default')","preventionTips":["Register custom themes in on_mount before any theme assignment","Source theme names from available_themes in settings UIs"],"tags":["theme","reactive-validation","textual"],"backgroundTag":"unregistered-theme-name","analyzedSha":"06dbeef4bb70fb718236aa418ed658ef4667a126","analyzedAt":"2026-08-27T02:36:57.214Z","schemaVersion":2},"datasetVersion":"2026-08-27T03:17:27.898Z"}