{"record":{"id":"29a707b4bf4fb156","repo":"pytest-dev/pytest","slug":"expected-id-to-be-a-string-or-a-pytest-hidden-par","errorCode":null,"errorMessage":"Expected id to be a string or a `pytest.HIDDEN_PARAM` sentinel, got {type(id)}: {id!r}","messagePattern":"Expected id to be a string or a `pytest\\.HIDDEN_PARAM` sentinel, got (.+?): (.+?)","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"src/_pytest/mark/structures.py","lineNumber":134,"sourceCode":"    def param(\n        cls,\n        *values: object,\n        marks: MarkDecorator | Collection[MarkDecorator | Mark] = (),\n        id: str | _HiddenParam | None = None,\n    ) -> ParameterSet:\n        if isinstance(marks, MarkDecorator):\n            marks = (marks,)\n        else:\n            assert isinstance(marks, collections.abc.Collection)\n        if any(i.name == \"usefixtures\" for i in marks):\n            raise ValueError(\n                \"pytest.param cannot add pytest.mark.usefixtures; see \"\n                \"https://docs.pytest.org/en/stable/reference/reference.html#pytest-param\"\n            )\n\n        if id is not None:\n            if not isinstance(id, str) and id is not HIDDEN_PARAM:\n                raise TypeError(\n                    \"Expected id to be a string or a `pytest.HIDDEN_PARAM` sentinel, \"\n                    f\"got {type(id)}: {id!r}\",\n                )\n        return cls(values, marks, id)\n\n    @classmethod\n    def extract_from(\n        cls,\n        parameterset: ParameterSet | Sequence[object] | object,\n        force_tuple: bool = False,\n    ) -> ParameterSet:\n        \"\"\"Extract from an object or objects.\n\n        :param parameterset:\n            A legacy style parameterset that may or may not be a tuple,\n            and may or may not be wrapped into a mess of mark objects.\n\n        :param force_tuple:","sourceCodeStart":116,"sourceCodeEnd":152,"githubUrl":"https://github.com/pytest-dev/pytest/blob/0d6fbdeffa57c796123f62f81f7dd370d9b7ecdc/src/_pytest/mark/structures.py#L116-L152","documentation":"A TypeError raised by ParameterSet.param when the `id` argument is not None, not a str, and not the HIDDEN_PARAM sentinel. pytest.param accepts only a string id (the displayed test id) or the special pytest.HIDDEN_PARAM marker to hide a parameter row. Any other type (int, float, list, None mismatch) fails this isinstance chain.","triggerScenarios":"Calling `pytest.param(1, id=42)`, `pytest.param(1, id=['a'])`, or `pytest.param(1, id=object())`. The guard `not isinstance(id, str) and id is not HIDDEN_PARAM` catches everything that is neither.","commonSituations":"Passing a numeric id expecting automatic string conversion, passing a list/tuple of id components, or passing None when meaning to omit the argument (None is allowed and means 'auto').","solutions":["Convert the id to a string: `id=str(value)`.","Omit the id argument entirely to let pytest generate one, or pass None explicitly.","Use `pytest.HIDDEN_PARAM` (newer pytest) only if you intend to hide the row."],"exampleFix":"# before\npytest.param(1, id=42)\n# after\npytest.param(1, id='42')","handlingStrategy":"type-guard","validationCode":"def coerce_param_id(id_value):\n    if id_value is None:\n        return None\n    return str(id_value) if not isinstance(id_value, str) else id_value","typeGuard":"def is_legal_param_id(id_value) -> bool:\n    return id_value is None or isinstance(id_value, str)","tryCatchPattern":null,"preventionTips":["Always pass strings as `id`; convert non-strings with str().","Omit `id` to use pytest's auto-generated ids.","Type-check ids built from dynamic data."],"tags":["pytest","parametrize","type-error","test-id","pytest-param"],"backgroundTag":null,"analyzedSha":"0d6fbdeffa57c796123f62f81f7dd370d9b7ecdc","analyzedAt":"2026-08-11T20:52:36.969Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}