pytest-dev/pytest · error · TypeError
nodeid or parent must be provided
Error message
nodeid or parent must be provided
What it means
Raised by Node.__init__ when nodeid is None and there is no parent to derive it from. At lines 198-202, if nodeid is given it is stored directly; otherwise the nodeid is computed as parent.nodeid + '::' + name. Without either source, the node cannot be uniquely identified in pytest's collection tree, so a TypeError is raised.
Solutions
- Provide a parent node so nodeid is derived automatically.
- Supply an explicit nodeid string when constructing standalone.
- Route construction through from_parent to inherit nodeid semantics.
Example fix
// before node = MyItem(name='test_foo') // after node = MyItem.from_parent(parent=parent_node, name='test_foo')
Defensive patterns
Strategy: validation
Validate before calling
if nodeid is None and parent is None:
raise TypeError('provide nodeid or parent') Type guard
def _nodeid_resolvable(nodeid, parent) -> bool:
return nodeid is not None or parent is not None Prevention
- Always supply a parent node; derive nodeid automatically.
- Provide an explicit nodeid only for special standalone cases.
When it happens
Trigger: Node(name='x') with nodeid=None and parent=None; constructing a node without a parent and without an explicit nodeid string.
Common situations: Plugin authors instantiating nodes directly rather than via from_parent; standalone node construction in tests that omit nodeid.
Related errors
- config is not a valid argument for from_parent
- config or parent must be provided
- session is not a valid argument for from_parent
- session or parent must be provided
- expected string as 'msg' parameter, got ' '…
AI-assisted analysis of pytest-dev/pytest@0d6fbdeffa (2026-08-11).
Data as JSON: /api/errors/cd34c7f1ea2364a8.
Report an issue: GitHub.
Appendix: source
Thrown at src/_pytest/nodes.py:200
#: Filesystem path where this node was collected from.
self.path: pathlib.Path = path
# The explicit annotation is to avoid publicly exposing NodeKeywords.
#: Keywords/markers collected from all scopes.
self.keywords: MutableMapping[str, Any] = NodeKeywords(self)
#: The marker objects belonging to this node.
self.own_markers: list[Mark] = []
#: Allow adding of extra keywords to use for matching.
self.extra_keyword_matches: set[str] = set()
if nodeid is not None:
assert "::()" not in nodeid
self._nodeid = nodeid
else:
if not self.parent:
raise TypeError("nodeid or parent must be provided")
self._nodeid = self.parent.nodeid + "::" + self.name
#: A place where plugins can store information on the node for their
#: own use.
self.stash: Stash = Stash()
# Deprecated alias. Was never public. Can be removed in a few releases.
self._store = self.stash
@classmethod
def from_parent(cls, parent: Node, **kw) -> Self:
"""Public constructor for Nodes.
This indirection got introduced in order to enable removing
the fragile logic from the node constructors.
Subclasses can use ``super().from_parent(...)`` when overriding the
construction.
View on GitHub (pinned to 0d6fbdeffa)