pytest-dev/pytest · error · ValueError

pytest_markeval_namespace() needs to return a dict, got {dic

Error message

pytest_markeval_namespace() needs to return a dict, got {dictionary!r}

What it means

Raised when pytest is evaluating a string condition on a skipif/xfail mark (e.g. @pytest.mark.skipif('sys.platform == "win32"')) and a registered pytest_markeval_namespace hook returns a value that is not a Mapping. The hook exists to inject names into the condition's eval namespace; pytest requires every hook implementation to return a dict so the namespace composition is well-defined.

Source

Thrown at src/_pytest/skipping.py:110

    If an old-style string condition is given, it is eval()'d, otherwise the
    condition is bool()'d. If this fails, an appropriately formatted pytest.fail
    is raised.

    Returns (result, reason). The reason is only relevant if the result is True.
    """
    # String condition.
    if isinstance(condition, str):
        globals_ = {
            "os": os,
            "sys": sys,
            "platform": platform,
            "config": item.config,
        }
        for dictionary in reversed(
            item.ihook.pytest_markeval_namespace(config=item.config)
        ):
            if not isinstance(dictionary, Mapping):
                raise ValueError(
                    f"pytest_markeval_namespace() needs to return a dict, got {dictionary!r}"
                )
            globals_.update(dictionary)
        if hasattr(item, "obj"):
            globals_.update(item.obj.__globals__)
        try:
            filename = f"<{mark.name} condition>"
            condition_code = compile(condition, filename, "eval")
            result = eval(condition_code, globals_)
        except SyntaxError as exc:
            msglines = [
                f"Error evaluating {mark.name!r} condition",
                "    " + condition,
                "    " + " " * (exc.offset or 0) + "^",
                "SyntaxError: invalid syntax",
            ]
            fail("\n".join(msglines), pytrace=False)
        except Exception as exc:

View on GitHub (pinned to 98b357f69e)

Solutions

  1. Change the hook to `return {...}` (a dict) for every code path.
  2. If you want to contribute no names, return an empty dict rather than None.
  3. Audit all conftest.py files and installed plugins that define pytest_markeval_namespace.
  4. Run `pytest --trace-config` to list hook implementations and confirm which one returns the bad value.

Example fix

// before
def pytest_markeval_namespace(config):
    return [("VERSION", 42)]  # wrong: list

// after
def pytest_markeval_namespace(config):
    return {"VERSION": 42}
Defensive patterns

Strategy: validation

Validate before calling

from collections.abc import Mapping

def pytest_markeval_namespace(config):
    ns = compute_namespace()
    assert isinstance(ns, Mapping), f"markeval namespace must be a Mapping, got {type(ns)!r}"
    return ns

Type guard

from collections.abc import Mapping
from typing import Any

def is_namespace_dict(v: Any) -> bool:
    return isinstance(v, Mapping)

Prevention

When it happens

Trigger: A conftest.py or plugin implements pytest_markeval_namespace(config) and returns a list, None, or a custom non-Mapping object. The error fires only when a string-condition skipif/xfail mark is being evaluated, because that is when the hook results are consumed.

Common situations: Porting an old plugin that returned a list of names instead of a dict; typo returning the internal list of (name, value) pairs; a hook that conditionally returns None when it should return {}.

Related errors


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