{"id":"4bf43087638a136e","repo":"pytest-dev/pytest","slug":"pytest-markeval-namespace-needs-to-return-a-dict","errorCode":null,"errorMessage":"pytest_markeval_namespace() needs to return a dict, got {dictionary!r}","messagePattern":"pytest_markeval_namespace\\(\\) needs to return a dict, got (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/_pytest/skipping.py","lineNumber":110,"sourceCode":"    If an old-style string condition is given, it is eval()'d, otherwise the\n    condition is bool()'d. If this fails, an appropriately formatted pytest.fail\n    is raised.\n\n    Returns (result, reason). The reason is only relevant if the result is True.\n    \"\"\"\n    # String condition.\n    if isinstance(condition, str):\n        globals_ = {\n            \"os\": os,\n            \"sys\": sys,\n            \"platform\": platform,\n            \"config\": item.config,\n        }\n        for dictionary in reversed(\n            item.ihook.pytest_markeval_namespace(config=item.config)\n        ):\n            if not isinstance(dictionary, Mapping):\n                raise ValueError(\n                    f\"pytest_markeval_namespace() needs to return a dict, got {dictionary!r}\"\n                )\n            globals_.update(dictionary)\n        if hasattr(item, \"obj\"):\n            globals_.update(item.obj.__globals__)\n        try:\n            filename = f\"<{mark.name} condition>\"\n            condition_code = compile(condition, filename, \"eval\")\n            result = eval(condition_code, globals_)\n        except SyntaxError as exc:\n            msglines = [\n                f\"Error evaluating {mark.name!r} condition\",\n                \"    \" + condition,\n                \"    \" + \" \" * (exc.offset or 0) + \"^\",\n                \"SyntaxError: invalid syntax\",\n            ]\n            fail(\"\\n\".join(msglines), pytrace=False)\n        except Exception as exc:","sourceCodeStart":92,"sourceCodeEnd":128,"githubUrl":"https://github.com/pytest-dev/pytest/blob/98b357f69e380da908740a212288d73b2ee06687/src/_pytest/skipping.py#L92-L128","documentation":"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.","triggerScenarios":"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.","commonSituations":"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 {}.","solutions":["Change the hook to `return {...}` (a dict) for every code path.","If you want to contribute no names, return an empty dict rather than None.","Audit all conftest.py files and installed plugins that define pytest_markeval_namespace.","Run `pytest --trace-config` to list hook implementations and confirm which one returns the bad value."],"exampleFix":"// before\ndef pytest_markeval_namespace(config):\n    return [(\"VERSION\", 42)]  # wrong: list\n\n// after\ndef pytest_markeval_namespace(config):\n    return {\"VERSION\": 42}","handlingStrategy":"validation","validationCode":"from collections.abc import Mapping\n\ndef pytest_markeval_namespace(config):\n    ns = compute_namespace()\n    assert isinstance(ns, Mapping), f\"markeval namespace must be a Mapping, got {type(ns)!r}\"\n    return ns","typeGuard":"from collections.abc import Mapping\nfrom typing import Any\n\ndef is_namespace_dict(v: Any) -> bool:\n    return isinstance(v, Mapping)","tryCatchPattern":null,"preventionTips":["Always return a dict literal from pytest_markeval_namespace, even when empty.","Add a unit test that calls your hook and asserts the return type is Mapping.","Document the contract in the plugin README so contributors do not regress it."],"tags":["marks","skipif","xfail","hooks","markeval"],"analyzedSha":"98b357f69e380da908740a212288d73b2ee06687","analyzedAt":"2026-08-04T20:26:34.442Z","schemaVersion":2}