apache/superset · error · ThemeNotFoundError

Theme not found.

Error message

Theme not found.

What it means

Raised by SetSystemThemeCommand.validate() when ThemeDAO.find_by_id(theme_id) returns None. The command that sets a theme as the system default first resolves the theme by primary key; a missing row aborts before any DB write with ThemeNotFoundError (HTTP 404-mapped, surfaced as 'Theme not found.'

Source

Thrown at superset/commands/theme/set_system_theme.py:61

        # Clear all existing system defaults in a single query
        db.session.execute(
            update(Theme)
            .where(Theme.is_system_default.is_(True))
            .values(is_system_default=False)
        )

        # Set the new system default
        self._theme.is_system_default = True
        db.session.add(self._theme)

        logger.info("Set theme %s as system default", self._theme_id)

        return self._theme

    def validate(self) -> None:
        self._theme = ThemeDAO.find_by_id(self._theme_id)
        if not self._theme:
            raise ThemeNotFoundError()


class SetSystemDarkThemeCommand(BaseCommand):
    def __init__(self, theme_id: int):
        self._theme_id = theme_id
        self._theme: Optional[Theme] = None

    @transaction(on_error=partial(on_error, reraise=Exception))
    def run(self) -> Theme:
        self.validate()
        assert self._theme

        # Clear all existing system dark themes in a single query
        db.session.execute(
            update(Theme)
            .where(Theme.is_system_dark.is_(True))
            .values(is_system_dark=False)
        )

View on GitHub (pinned to f4587218dd)

Solutions

  1. Verify the theme exists first: GET the theme by the same ID before issuing the set-system-default call.
  2. If the ID came from a cached list, refresh the theme list and retry with the current ID.
  3. If this happens in tests, re-seed or re-create themes in setup so the referenced ID is valid.
  4. Check for concurrent deletion: query the theme table for the ID and re-create the theme if it was removed.

Example fix

# before
SetSystemThemeCommand(theme_id=99).run()  # 99 does not exist

# after
from superset.daos.theme import ThemeDAO
if ThemeDAO.find_by_id(99) is None:
    raise ValueError("theme 99 missing; refresh theme list")
SetSystemThemeCommand(theme_id=99).run()
Defensive patterns

Strategy: validation

Validate before calling

from superset.daos.theme import ThemeDAO
if ThemeDAO.find_by_id(theme_id) is None:
    raise LookupError(f"theme {theme_id} not found")

Try / catch

from superset.commands.theme.exceptions import ThemeNotFoundError
try:
    SetSystemThemeCommand(theme_id).run()
except ThemeNotFoundError:
    reload_themes_and_retry_once()

Prevention

When it happens

Trigger: Calling the theme API endpoint that sets the system default theme (e.g. PUT/POST on /api/v1/theme/... set-system-default route) with a theme_id that does not exist in the theme table, or with an ID of a theme deleted by another user between listing and calling.

Common situations: Stale frontend state after a theme was deleted; passing an internal integer ID from an outdated cache; test fixtures that reference seeded theme IDs that no longer exist after a DB reset or migration.

Related errors


AI-assisted analysis of apache/superset@f4587218dd (2026-08-14). Data as JSON: /api/errors/cf25277a374eda68. Report an issue: GitHub.