pytest-dev/pytest · error · TypeError

use setattr(target, name, value) with name being a string…

Error message

use setattr(target, name, value) with name being a string or setattr(target, value) with target being a dotted import string

What it means

A TypeError raised by MonkeyPatch.setattr when the three-argument form is used (value is provided) but the `name` argument is not a string. pytest requires the attribute name to be a string when patching a concrete target object. Passing an int, None, or any non-string as the name triggers this guard.

Solutions

  1. Ensure the second positional argument (name) is a string naming the attribute.
  2. If the name is dynamic, coerce to str or validate before calling.
  3. Double-check argument order: (target, name, value).

Example fix

# before
monkeypatch.setattr(obj, attr_name if cond else None, value)
# after
monkeypatch.setattr(obj, str(attr_name), value)
Defensive patterns

Strategy: type-guard

Validate before calling

def is_setattr_name(name) -> bool:
    return isinstance(name, str)

Type guard

def is_valid_attribute_name(name) -> bool:
    return isinstance(name, str) and len(name) > 0

Prevention

When it happens

Trigger: Calling `monkeypatch.setattr(obj, 123, value)`, `monkeypatch.setattr(obj, None, value)`, or `monkeypatch.setattr(obj, ['attr'], value)`. The branch `value is not NOTSET and not isinstance(name, str)` fires.

Common situations: Passing a computed attribute name that is None; mixing positional arguments; confusing the order of (target, name, value).

Related errors


AI-assisted analysis of pytest-dev/pytest@0d6fbdeffa (2026-08-11). Data as JSON: /api/errors/f599fc6dd3fc243f. Report an issue: GitHub.

Appendix: source

Thrown at src/_pytest/monkeypatch.py:234

        See the section :ref:`Where to patch <python:where-to-patch>` in the :mod:`unittest.mock`
        docs for a complete explanation, which is meant for :func:`unittest.mock.patch` but
        applies to ``monkeypatch.setattr`` as well.
        """
        __tracebackhide__ = True
        import inspect

        if value is NOTSET:
            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,

View on GitHub (pinned to 0d6fbdeffa)