pytest-dev/pytest · error · AttributeError

{target!r} has no attribute {name!r}

Error message

{target!r} has no attribute {name!r}

What it means

In `monkeypatch.setattr`, after resolving target+name, pytest checks the existing attribute. With `raising=True` (the default), if the attribute is not present on the target it raises `AttributeError: <target> has no attribute <name>`. This is the guard against patching non-existent attributes, which usually signals a typo or wrong patch location.

Source

Thrown at src/_pytest/monkeypatch.py:242

            if not isinstance(target, str):
                raise TypeError(
                    "use setattr(target, name, value) or "
                    "setattr(target, value) with target being a dotted "
                    "import string"
                )
            value = name
            name, target = derive_importpath(target, raising)
        else:
            if not isinstance(name, str):
                raise TypeError(
                    "use setattr(target, name, value) with name being a string or "
                    "setattr(target, value) with target being a dotted "
                    "import string"
                )

        oldval = getattr(target, name, NOTSET)
        if raising and oldval is NOTSET:
            raise AttributeError(f"{target!r} has no attribute {name!r}")

        # avoid class descriptors like staticmethod/classmethod
        if inspect.isclass(target):
            oldval = target.__dict__.get(name, NOTSET)
        setattr(target, name, value)
        self._setattr.append((target, name, oldval))

    def delattr(
        self,
        target: object | str,
        name: str | NotSetType = NOTSET,
        raising: bool = True,
    ) -> None:
        """Delete attribute ``name`` from ``target``.

        If no ``name`` is specified and ``target`` is a string
        it will be interpreted as a dotted import path with the
        last part being the attribute name.

View on GitHub (pinned to 98b357f69e)

Solutions

  1. Patch the name where it is looked up (e.g. `mypkg.mod.os` if `myobj` does `import os` there).
  2. Set `raising=False` if you intentionally create a new attribute.
  3. Verify with `hasattr(target, name)` before patching to get a clearer assertion.

Example fix

# before
monkeypatch.setattr(mymod, 'requests.get', fake)  # nested path not an attribute
# after
import mymod.requests as r
monkeypatch.setattr(r, 'get', fake)
Defensive patterns

Strategy: validation

Validate before calling

def safe_to_patch(target, name) -> bool:
    return hasattr(target, name)

Try / catch

try:
    monkeypatch.setattr(target, name, fake)
except AttributeError:
    # patch the using module instead, or pass raising=False to create
    monkeypatch.setattr(target, name, fake, raising=False)

Prevention

When it happens

Trigger: `monkeypatch.setattr(myobj, 'nonexistent', fake)` with default `raising=True`; patching an attribute introduced only after some runtime setup that hasn't happened.

Common situations: Patching the wrong module (the classic 'where to patch' problem — patching the using module vs the defining module); typos; version skew where the attribute was removed.

Related errors


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