{"record":{"id":"bb147564fbedcd9f","repo":"pytest-dev/pytest","slug":"warning-must-be-str-or-warning-got-msg-r-type","errorCode":null,"errorMessage":"Warning must be str or Warning, got {msg!r} (type {type(msg).__name__})","messagePattern":"Warning must be str or Warning, got (.+?) \\(type (.+?)\\)","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"src/_pytest/recwarn.py","lineNumber":376,"sourceCode":"            # While this can be considered a bug in CPython, we put guards in\n            # pytest as the error message produced without this check in place\n            # is confusing (#10865).\n            for w in self:\n                if type(w.message) is not UserWarning:\n                    # If the warning was of an incorrect type then `warnings.warn()`\n                    # creates a UserWarning. Any other warning must have been specified\n                    # explicitly.\n                    continue\n                if not w.message.args:\n                    # UserWarning() without arguments must have been specified explicitly.\n                    continue\n                msg = w.message.args[0]\n                if isinstance(msg, str):\n                    continue\n                # It's possible that UserWarning was explicitly specified, and\n                # its first argument was not a string. But that case can't be\n                # distinguished from an invalid type.\n                raise TypeError(\n                    f\"Warning must be str or Warning, got {msg!r} (type {type(msg).__name__})\"\n                )\n","sourceCodeStart":358,"sourceCodeEnd":379,"githubUrl":"https://github.com/pytest-dev/pytest/blob/0d6fbdeffa57c796123f62f81f7dd370d9b7ecdc/src/_pytest/recwarn.py#L358-L379","documentation":"Raised in WarningsChecker.__exit__ during re-emission of unmatched warnings when a recorded UserWarning's first argument is not a str. CPython's warnings.filterwarnings cannot filter non-str warning messages, producing a confusing error; pytest surfaces it earlier with the actual value and type. It applies only to UserWarning (the default category) whose message args are non-empty and non-str.","triggerScenarios":"Code under test calls warnings.warn(123) or warnings.warn(some_object) without a category, producing a UserWarning whose message arg is non-str; explicitly emitting UserWarning(non_str).","commonSituations":"Libraries that pass non-str payloads to warnings.warn (e.g. an error code or dataclass); third-party code emitting UserWarning with structured args; CPython bug workaround per #103577.","solutions":["Emit warnings with a str message: warnings.warn('deprecated', DeprecationWarning).","If you need a structured payload, format it to str first: warnings.warn(f'code={code}', UserWarning).","If the offending emission is in third-party code you cannot change, filter it before pytest.warns runs (e.g. warnings.filterwarnings)."],"exampleFix":"// before\nwarnings.warn(response_payload)  # response_payload is a dict\n// after\nwarnings.warn(str(response_payload), UserWarning)","handlingStrategy":"validation","validationCode":"import warnings as _w\n# before the warned call, ensure callers emit str messages;\n# if intercepting, normalize:\norig_warn = _w.warn\ndef _str_warn(message, *a, **k):\n    if not isinstance(message, str) and not isinstance(message, Warning):\n        message = str(message)\n    return orig_warn(message, *a, **k)","typeGuard":"def warn_message_is_str_or_warning(message) -> bool:\n    return isinstance(message, (str, Warning))","tryCatchPattern":null,"preventionTips":["Always emit warnings with a str message: warnings.warn('text', Category).","Avoid passing dataclasses/enums/ints as the warning message.","If third-party code emits non-str UserWarning args, filter it before pytest.warns runs."],"tags":["pytest","warns","warning-message","non-str","cpupn-workaround"],"backgroundTag":null,"analyzedSha":"0d6fbdeffa57c796123f62f81f7dd370d9b7ecdc","analyzedAt":"2026-08-11T20:52:36.969Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}