{"record":{"id":"82dd1f34fe85078c","repo":"python/cpython","slug":"expected-theme-object-found-t","errorCode":null,"errorMessage":"Expected Theme object, found {t}","messagePattern":"Expected Theme object, found (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"Lib/_colorize.py","lineNumber":643,"sourceCode":"    See `Theme.no_colors()` for more information.\n\n    It is recommended not to cache the result of this function for extended\n    periods of time because the user might influence theme selection by\n    the interactive shell, a debugger, or application-specific code. The\n    environment (including environment variable state and console configuration\n    on Windows) can also change in the course of the application life cycle.\n    \"\"\"\n    if force_color or (not force_no_color and\n                       can_colorize(file=tty_file)):\n        return _theme\n    return theme_no_color\n\n\ndef set_theme(t: Theme) -> None:\n    global _theme\n\n    if not isinstance(t, Theme):\n        raise ValueError(f\"Expected Theme object, found {t}\")\n\n    _theme = t\n\n\nset_theme(default_theme)\n","sourceCodeStart":625,"sourceCodeEnd":649,"githubUrl":"https://github.com/python/cpython/blob/bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6/Lib/_colorize.py#L625-L649","documentation":"ValueError raised by _colorize.set_theme() (Lib/_colorize.py) when the argument is not an instance of the internal _colorize.Theme class. set_theme is the single hook for replacing the interpreter's color theme; it deliberately rejects dicts, strings, and third-party look-alikes so that THEME_TOKEN-based rendering never receives an unknown object.","triggerScenarios":"Calling _colorize.set_theme({'subject': {'fg': 'blue'}}) or set_theme('monokai') — anything that is not a Theme instance. Also wrapping or copying themes: a subclass of Theme is accepted, but duck-typed objects are not.","commonSituations":"Users trying to customize PYTHON_COLORS_REPL/theme output by poking at _colorize; scripts copying a theme dict out of _colorize.themes and feeding it back; third-party REPL/tools integrating CPython's colorizer and assuming a mapping API.","solutions":["Pass an actual _colorize.Theme: t = _colorize.themes['neutral']; _colorize.set_theme(t) (or a copy you mutate via Theme construction), not a dict.","To tweak, start from an existing Theme and construct a new Theme with modified token rules rather than a plain mapping.","If you only want colors on/off, use environment controls (PYTHON_COLORS=0/1, NO_COLOR, FORCE_COLOR) or initialize(...) flags instead of swapping themes.","Register custom themes at startup via the documented theme hook (e.g. PYTHON_COLORS_THEME / user theme registration) rather than ad-hoc objects."],"exampleFix":"# before\nimport _colorize\n_colorize.set_theme({'subject': {'fg': 'green'}})  # ValueError: Expected Theme object\n\n# after\nimport _colorize\ntheme = _colorize.themes['neutral']\n_colorize.set_theme(theme)  # a real Theme instance","handlingStrategy":"type-guard","validationCode":"import _colorize\n\ndef theme_ok(t) -> bool:\n    return isinstance(t, _colorize.Theme)","typeGuard":"import _colorize\n\ndef is_theme(t) -> bool:\n    \"\"\"Type guard: True only for real _colorize Theme instances.\"\"\"\n    return isinstance(t, _colorize.Theme)","tryCatchPattern":"try:\n    _colorize.set_theme(candidate)\nexcept ValueError as e:\n    if 'Expected Theme object' in str(e):\n        _colorize.set_theme(_colorize.themes['neutral'])  # known-good Theme\n    else:\n        raise","preventionTips":["Only pass Theme objects obtained from _colorize.themes or constructed via Theme.","Prefer environment toggles (PYTHON_COLORS, NO_COLOR) over swapping themes.","Treat _colorize as CPython-internal; pin behavior to the exact interpreter version."],"tags":["colorize","cpython-internals","terminal","developer-error"],"backgroundTag":null,"analyzedSha":"bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6","analyzedAt":"2026-08-14T22:01:13.976Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}