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
- Verify the theme exists first: GET the theme by the same ID before issuing the set-system-default call.
- If the ID came from a cached list, refresh the theme list and retry with the current ID.
- If this happens in tests, re-seed or re-create themes in setup so the referenced ID is valid.
- 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
- Fetch theme by ID before issuing set-default commands
- Never cache theme integer IDs across sessions
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
- Theme not found.
- Cannot modify system themes.
- Datasource does not exist
- Tag ID {tag_id} not found
- Chart with ID {annotation_layer["value"]} (referenced by ann
AI-assisted analysis of apache/superset@f4587218dd (2026-08-14).
Data as JSON: /api/errors/cf25277a374eda68.
Report an issue: GitHub.