pytest-dev/pytest · error · TypeError
expected string as 'msg' parameter, got ' '…
Error message
{} expected string as 'msg' parameter, got '{}' instead.
Perhaps you meant to use a mark? What it means
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.
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.
Example fix
// before pytest.skip(some_exception) // after pytest.skip(str(some_exception))
Defensive patterns
Strategy: type-guard
Validate before calling
if msg is not None and not isinstance(msg, str):
msg = str(msg) Type guard
def _outcome_msg_ok(msg) -> bool:
return msg is None or isinstance(msg, str) Prevention
- Pass only string reasons to pytest.skip/fail/xfail.
- Convert exceptions to str before using as a reason.
When it happens
Trigger: pytest.skip(some_object); pytest.fail(an_exception); pytest.xfail(123); passing a Mark or a non-string payload to an outcome function.
Common situations: Developers call pytest.skip(exception) intending to re-raise an exception; passing a mark object; passing a dict of context as the reason.
Related errors
- use delattr(target, name) or delattr(target) with target…
- config is not a valid argument for from_parent
- config or parent must be provided
- object (type: ) must be callable
- module has __version__ , required is
AI-assisted analysis of pytest-dev/pytest@0d6fbdeffa (2026-08-11).
Data as JSON: /api/errors/9e8a88e10b26884f.
Report an issue: GitHub.
Appendix: source
Thrown at src/_pytest/outcomes.py:23
import importlib
import sys
from typing import Any
from typing import ClassVar
from typing import NoReturn
class OutcomeException(BaseException):
"""OutcomeException and its subclass instances indicate and contain info
about test and collection outcomes."""
def __init__(self, msg: str | None = None, pytrace: bool = True) -> None:
if msg is not None and not isinstance(msg, str):
error_msg = ( # type: ignore[unreachable]
"{} expected string as 'msg' parameter, got '{}' instead.\n"
"Perhaps you meant to use a mark?"
)
raise TypeError(error_msg.format(type(self).__name__, type(msg).__name__))
super().__init__(msg)
self.msg = msg
self.pytrace = pytrace
def __repr__(self) -> str:
if self.msg is not None:
return self.msg
return f"<{self.__class__.__name__} instance>"
__str__ = __repr__
TEST_OUTCOME = (OutcomeException, Exception)
class Skipped(OutcomeException):
# XXX hackish: on 3k we fake to live in the builtins
# in order to have Skipped exception printing shorter/nicerView on GitHub (pinned to 0d6fbdeffa)