{"record":{"id":"82d4e7ea2961cf63","repo":"python/cpython","slug":"category-must-be-a-warning-subclass-not-type-ca","errorCode":null,"errorMessage":"category must be a Warning subclass, not '{type(category).__name__}'","messagePattern":"category must be a Warning subclass, not '(.+?)'","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"Lib/_py_warnings.py","lineNumber":475,"sourceCode":"    while frame is not None and (\n            _is_internal_filename(filename := frame.f_code.co_filename) or\n            _is_filename_to_skip(filename, skip_file_prefixes)):\n        frame = frame.f_back\n    return frame\n\n\n# Code typically replaced by _warnings\ndef warn(message, category=None, stacklevel=1, source=None,\n         *, skip_file_prefixes=()):\n    \"\"\"Issue a warning, or maybe ignore it or raise an exception.\"\"\"\n    # Check if message is already a Warning object\n    if isinstance(message, Warning):\n        category = message.__class__\n    # Check category argument\n    if category is None:\n        category = UserWarning\n    elif not isinstance(category, type):\n        raise TypeError(f\"category must be a Warning subclass, not \"\n                        f\"'{type(category).__name__}'\")\n    elif not issubclass(category, Warning):\n        raise TypeError(f\"category must be a Warning subclass, not \"\n                        f\"class '{category.__name__}'\")\n    if not isinstance(skip_file_prefixes, tuple):\n        # The C version demands a tuple for implementation performance.\n        raise TypeError('skip_file_prefixes must be a tuple of strs.')\n    if skip_file_prefixes:\n        stacklevel = max(2, stacklevel)\n    # Get context information\n    try:\n        if stacklevel <= 1 or _is_internal_frame(sys._getframe(1)):\n            # If frame is too small to care or if the warning originated in\n            # internal code, then do not try to hide any frames.\n            frame = sys._getframe(stacklevel)\n        else:\n            frame = sys._getframe(1)\n            # Look for one frame less since the above line starts us off.","sourceCodeStart":457,"sourceCodeEnd":493,"githubUrl":"https://github.com/python/cpython/blob/bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6/Lib/_py_warnings.py#L457-L493","documentation":"Raised by the pure-Python warnings.warn fallback when the category argument is not a type at all — e.g. a string like 'DeprecationWarning' or an instance like UserWarning('x'). warn() needs a class it can instantiate with the message, so a non-class category fails fast with TypeError. The companion check at the next branch covers classes that are types but not Warning subclasses.","triggerScenarios":"warnings.warn('msg', 'DeprecationWarning'); warnings.warn('msg', SomeWarning('extra')); forwarding a category that arrived as text from config/logging records.","commonSituations":"String category names from log records, serialization layers, or CLI options passed straight to warn; instantiating the category out of habit; dynamically built warn wrappers that lose track of whether they hold a name or a class.","solutions":["Pass the class: warnings.warn('msg', DeprecationWarning)","Resolve names to classes first: importlib + getattr on the warnings module, then verify it is a Warning subclass","If the value is already a Warning instance, pass it as the message: warnings.warn(instance) uses its class"],"exampleFix":"# before\nwarnings.warn('feature X is going away', 'DeprecationWarning')  # TypeError\n\n# after\nwarnings.warn('feature X is going away', DeprecationWarning)","handlingStrategy":"type-guard","validationCode":"import warnings\n\ndef warn_with_category(message, category):\n    if isinstance(message, Warning):\n        return warnings.warn(message)\n    if isinstance(category, str):\n        category = getattr(warnings, category, None) or __import__('builtins').__dict__.get(category)\n    if not (isinstance(category, type) and issubclass(category, Warning)):\n        raise TypeError(f'category must be a Warning subclass, got {category!r}')\n    return warnings.warn(message, category)","typeGuard":"def is_warning_class(cat) -> bool:\n    return isinstance(cat, type) and issubclass(cat, Warning)","tryCatchPattern":null,"preventionTips":["Pass Warning classes (DeprecationWarning, UserWarning, ...) — not names, not instances","If the value is already a Warning instance, pass it as the message: warn(instance)","Resolve category strings at the config boundary and fail fast there"],"tags":["warnings","validation","category"],"backgroundTag":null,"analyzedSha":"bc6749cc3b5ae4a5e88a6cc2d5b3bebbe354eae6","analyzedAt":"2026-08-14T22:01:13.976Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}