{"record":{"id":"9e8a88e10b26884f","repo":"pytest-dev/pytest","slug":"expected-string-as-msg-parameter-got-in","errorCode":null,"errorMessage":"{} expected string as 'msg' parameter, got '{}' instead.\nPerhaps you meant to use a mark?","messagePattern":"(.+?) expected string as 'msg' parameter, got '(.+?)' instead\\.\nPerhaps you meant to use a mark\\?","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"src/_pytest/outcomes.py","lineNumber":23,"sourceCode":"\nimport importlib\nimport sys\nfrom typing import Any\nfrom typing import ClassVar\nfrom typing import NoReturn\n\n\nclass OutcomeException(BaseException):\n    \"\"\"OutcomeException and its subclass instances indicate and contain info\n    about test and collection outcomes.\"\"\"\n\n    def __init__(self, msg: str | None = None, pytrace: bool = True) -> None:\n        if msg is not None and not isinstance(msg, str):\n            error_msg = (  # type: ignore[unreachable]\n                \"{} expected string as 'msg' parameter, got '{}' instead.\\n\"\n                \"Perhaps you meant to use a mark?\"\n            )\n            raise TypeError(error_msg.format(type(self).__name__, type(msg).__name__))\n        super().__init__(msg)\n        self.msg = msg\n        self.pytrace = pytrace\n\n    def __repr__(self) -> str:\n        if self.msg is not None:\n            return self.msg\n        return f\"<{self.__class__.__name__} instance>\"\n\n    __str__ = __repr__\n\n\nTEST_OUTCOME = (OutcomeException, Exception)\n\n\nclass Skipped(OutcomeException):\n    # XXX hackish: on 3k we fake to live in the builtins\n    # in order to have Skipped exception printing shorter/nicer","sourceCodeStart":5,"sourceCodeEnd":41,"githubUrl":"https://github.com/pytest-dev/pytest/blob/0d6fbdeffa57c796123f62f81f7dd370d9b7ecdc/src/_pytest/outcomes.py#L5-L41","documentation":"Raised by OutcomeException.__init__ (parent of Skipped, Failed, XFailed) when msg is not None and not a str. The constructor at lines 18-23 enforces that msg be a string because outcome messages are rendered into reports and tracebacks; a non-string msg usually signals a misuse where a mark or object was passed instead. The error is raised eagerly as TypeError.","triggerScenarios":"pytest.skip(some_object); pytest.fail(an_exception); pytest.xfail(123); passing a Mark or a non-string payload to an outcome function.","commonSituations":"Developers call pytest.skip(exception) intending to re-raise an exception; passing a mark object; passing a dict of context as the reason.","solutions":["Pass a string reason: pytest.skip('reason text').","If propagating an exception, convert it: pytest.skip(str(exc)).","Use pytest.fail or pytest.raises appropriately rather than stuffing objects into msg."],"exampleFix":"// before\npytest.skip(some_exception)\n// after\npytest.skip(str(some_exception))","handlingStrategy":"type-guard","validationCode":"if msg is not None and not isinstance(msg, str):\n    msg = str(msg)","typeGuard":"def _outcome_msg_ok(msg) -> bool:\n    return msg is None or isinstance(msg, str)","tryCatchPattern":null,"preventionTips":["Pass only string reasons to pytest.skip/fail/xfail.","Convert exceptions to str before using as a reason."],"tags":["pytest","outcomes","typeerror","api-misuse"],"backgroundTag":null,"analyzedSha":"0d6fbdeffa57c796123f62f81f7dd370d9b7ecdc","analyzedAt":"2026-08-11T20:52:36.969Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}