pytest-dev/pytest · error · TypeError

nodeid or parent must be provided

Error message

nodeid or parent must be provided

What it means

Node.__init__ builds the node's nodeid from parent.nodeid + '::' + name when no explicit nodeid is given. With neither a parent nor an explicit nodeid the id cannot be derived, so pytest raises TypeError.

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 98b357f69e)

Solutions

  1. Pass a parent node so nodeid is derived: MyNode(name, parent=parent_node)
  2. For a root node pass nodeid explicitly, e.g. MyNode('name', config=cfg, session=s, nodeid='name')

Example fix

// before
node = MyNode('root', config=cfg, session=s)
// after
node = MyNode('root', config=cfg, session=s, nodeid='root')
Defensive patterns

Strategy: validation

Validate before calling

def make_node(cls, name, *, parent=None, nodeid=None, **kw):
    if parent is None and not nodeid:
        raise TypeError("provide parent or nodeid")
    return cls(name, parent=parent, nodeid=nodeid, **kw)

Type guard

def has_parent_or_nodeid(parent, nodeid) -> bool:
    return parent is not None or bool(nodeid)

Prevention

When it happens

Trigger: Constructing a root-level Node with no parent and no nodeid keyword, e.g. MyNode('name', config=cfg, session=s) but nodeid omitted.

Common situations: Plugin authors creating top-level nodes (e.g. a custom Session child) without passing nodeid; incomplete constructor migration.

Related errors


AI-assisted analysis of pytest-dev/pytest@98b357f69e (2026-08-04). Data as JSON: /data/errors/cd34c7f1ea2364a8.json. Report an issue: GitHub.