Textualize/rich · error · ThemeStackError

Unable to pop base theme

Error message

Unable to pop base theme

What it means

ThemeStack keeps a list of pushed theme dicts, always retaining the single base theme as the bottom entry. pop_theme() refuses to pop when len(_entries) == 1 — removing the base would leave the stack with no styles at all — raising ThemeStackError('Unable to pop base theme').

Source

Thrown at rich/theme.py:109

    def push_theme(self, theme: Theme, inherit: bool = True) -> None:
        """Push a theme on the top of the stack.

        Args:
            theme (Theme): A Theme instance.
            inherit (boolean, optional): Inherit styles from current top of stack.
        """
        styles: Dict[str, Style]
        styles = (
            {**self._entries[-1], **theme.styles} if inherit else theme.styles.copy()
        )
        self._entries.append(styles)
        self.get = self._entries[-1].get

    def pop_theme(self) -> None:
        """Pop (and discard) the top-most theme."""
        if len(self._entries) == 1:
            raise ThemeStackError("Unable to pop base theme")
        self._entries.pop()
        self.get = self._entries[-1].get


if __name__ == "__main__":  # pragma: no cover
    theme = Theme()
    print(theme.config)

View on GitHub (pinned to 9d8f9a372c)

Solutions

  1. Match every pop_theme() with exactly one push_theme(); prefer a try/finally around the themed block.
  2. Track nesting depth yourself, or guard: pop only if you know you pushed (pass/return a token).
  3. If you need the base theme back without popping, just push the default theme instead of popping past the base.

Example fix

# before
console.pop_theme()  # extra pop -> ThemeStackError

# after
console.push_theme(my_theme)
try:
    ...
finally:
    console.pop_theme()  # exactly one pop per push
Defensive patterns

Strategy: try-catch

Validate before calling

from rich.theme import ThemeStackError
# count pushes if you must pop conditionally
pushed = getattr(console, '_thread_pushes', 0)  # not exposed; track yourself:

Try / catch

from rich.theme import ThemeStackError
try:
    console.pop_theme()
except ThemeStackError:
    pass  # already at base theme

Prevention

When it happens

Trigger: Calling console.pop_theme() more times than push_theme() was called (unbalanced push/pop); popping on a fresh stack that never pushed; an exception path between push_theme and pop_theme that double-pops (e.g. finally-block pop after an early pop).

Common situations: Temporarily applying a theme around a code block (push/pop in try/finally) where a nested routine also pops; context-manager helper that pops in __exit__ being used without a matching enter; copy-paste of the push/pop snippet without the push line.

Related errors


AI-assisted analysis of Textualize/rich@9d8f9a372c (2026-08-15). Data as JSON: /api/errors/9ffa9720324114e8. Report an issue: GitHub.