Textualize/textual · error · InvalidThemeError

Theme {theme_name!r} has not been registered. Call 'App.regi

Error message

Theme {theme_name!r} has not been registered. Call 'App.register_theme' before setting the 'App.theme' attribute.

What it means

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.

Source

Thrown at src/textual/app.py:1500

        A dictionary mapping theme names to Theme instances.
        """
        return {**self._registered_themes}

    @property
    def current_theme(self) -> Theme:
        theme = self.get_theme(self.theme)
        if theme is None:
            theme = self.get_theme("textual-dark")
        assert theme is not None  # validated by _validate_theme
        return theme

    def _validate_theme(self, theme_name: str) -> str:
        if theme_name not in self.available_themes:
            message = (
                f"Theme {theme_name!r} has not been registered. "
                "Call 'App.register_theme' before setting the 'App.theme' attribute."
            )
            raise InvalidThemeError(message)
        return theme_name

    def _watch_theme(self, theme_name: str) -> None:
        """Apply a theme to the application.

        This method is called when the theme reactive attribute is set.
        """
        theme = self.current_theme
        dark = theme.dark
        # Setting the theme adds class "-theme-<THEME NAME>" to the App
        classes = {name: False for name in self.classes if name.startswith("-theme-")}
        classes[f"-theme-{self.current_theme.name}"] = True
        classes["-dark-mode"] = dark
        classes["-light-mode"] = not dark

        self.update_classes(classes, update=False)

        self._refresh_truecolor_filter(self.ansi_theme)

View on GitHub (pinned to 06dbeef4bb)

Solutions

  1. Register first: self.register_theme(Theme(name="my_custom", ...)) then self.theme = "my_custom"
  2. Check the name exists: assert name in self.available_themes before assigning
  3. For built-ins use exact names, e.g. "textual-dark", "gruvbox"

Example fix

# before
self.theme = "nord"  # not registered

# after
theme = Theme(name="nord", primary="#88C0D0")
self.register_theme(theme)
self.theme = "nord"
Defensive patterns

Strategy: validation

Validate before calling

if theme_name not in app.available_themes:
    app.register_theme(Theme(name=theme_name, primary="#..."))
app.theme = theme_name

Try / catch

try:
    self.app.theme = name
except InvalidThemeError:
    self.log.warning(f'theme {name} missing; keeping default')

Prevention

When it happens

Trigger: self.theme = "my_custom" without having called self.register_theme(Theme(...)); misspelling a built-in theme name like 'tokyo-night'.

Common situations: Adding custom themes after app startup; upgrading Textual where built-in theme names changed; setting theme from a config file value.

Related errors


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