pytest-dev/pytest · error · ValueError
is not a string or pytest.mark.* Marker
Error message
is not a string or pytest.mark.* Marker
What it means
Raised by Node.add_marker (via the marker path at lines 320-324) when the marker argument is neither a str nor a MarkDecorator. pytest accepts either a dotted-name string (resolved against MARK_GEN) or a MarkDecorator produced by pytest.mark.<name>. Any other type (int, dict, raw Mark, None) is rejected because it cannot be normalized to a marker.
Solutions
- Pass a string marker name: node.add_marker('skip').
- Pass a MarkDecorator from the mark generator: node.add_marker(pytest.mark.skip).
- If you hold a raw Mark, wrap it: MarkDecorator(mark) before adding.
Example fix
// before node.add_marker(my_mark.mark) // after from _pytest.mark import MarkDecorator node.add_marker(MarkDecorator(my_mark.mark))
Defensive patterns
Strategy: type-guard
Validate before calling
from _pytest.mark import MarkDecorator assert isinstance(marker, (str, MarkDecorator))
Type guard
def _is_valid_marker(marker) -> bool:
from _pytest.mark import MarkDecorator
return isinstance(marker, (str, MarkDecorator)) Prevention
- Prefer string marker names for add_marker.
- Distinguish Mark (raw) from MarkDecorator when constructing programmatically.
When it happens
Trigger: node.add_marker(42); node.add_marker({'name': 'skip'}); node.add_marker(some_mark.mark) passing a raw Mark instead of MarkDecorator; node.add_marker(None).
Common situations: Confusing Mark with MarkDecorator; passing a marker instance created via some_mark.args instead of pytest.mark.skip; programmatic marker construction errors.
Related errors
- warning must be an instance of Warning or subclass, got
- config is not a valid argument for from_parent
- config or parent must be provided
- nodeid or parent must be provided
- session is not a valid argument for from_parent
AI-assisted analysis of pytest-dev/pytest@0d6fbdeffa (2026-08-11).
Data as JSON: /api/errors/0aa1a81270f1bbbe.
Report an issue: GitHub.
Appendix: source
Thrown at src/_pytest/nodes.py:323
chain.reverse()
return chain
def add_marker(self, marker: str | MarkDecorator, append: bool = True) -> None:
"""Dynamically add a marker object to the node.
:param marker:
The marker.
:param append:
Whether to append the marker, or prepend it.
"""
from _pytest.mark import MARK_GEN
if isinstance(marker, MarkDecorator):
marker_ = marker
elif isinstance(marker, str):
marker_ = getattr(MARK_GEN, marker)
else:
raise ValueError("is not a string or pytest.mark.* Marker")
self.keywords[marker_.name] = marker_
if append:
self.own_markers.append(marker_.mark)
else:
self.own_markers.insert(0, marker_.mark)
def iter_markers(self, name: str | None = None) -> Iterator[Mark]:
"""Iterate over all markers of the node.
:param name: If given, filter the results by the name attribute.
:returns: An iterator of the markers of the node.
"""
return (x[1] for x in self.iter_markers_with_node(name=name))
def iter_markers_with_node(
self, name: str | None = None
) -> Iterator[tuple[Node, Mark]]:
"""Iterate over all markers of the node.View on GitHub (pinned to 0d6fbdeffa)