{"record":{"id":"1a2db5149e9289dc","repo":"pytest-dev/pytest","slug":"param-parameter-needs-to-be-a-string-but-g-gi","errorCode":null,"errorMessage":"{param} parameter needs to be a string, but {g} given","messagePattern":"(.+?) parameter needs to be a string, but (.+?) given","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"src/_pytest/junitxml.py","lineNumber":337,"sourceCode":"        pass\n\n    attr_func = add_attr_noop\n\n    xml = request.config.stash.get(xml_key, None)\n    if xml is not None:\n        node_reporter = xml.node_reporter(request.node.nodeid)\n        attr_func = node_reporter.add_attribute\n\n    return attr_func\n\n\ndef _check_record_param_type(param: str, v: str) -> None:\n    \"\"\"Used by record_testsuite_property to check that the given parameter name is of the proper\n    type.\"\"\"\n    __tracebackhide__ = True\n    if not isinstance(v, str):\n        msg = \"{param} parameter needs to be a string, but {g} given\"  # type: ignore[unreachable]\n        raise TypeError(msg.format(param=param, g=type(v).__name__))\n\n\n@pytest.fixture(scope=\"session\")\ndef record_testsuite_property(request: FixtureRequest) -> Callable[[str, object], None]:\n    \"\"\"Record a new ``<property>`` tag as child of the root ``<testsuite>``.\n\n    This is suitable to writing global information regarding the entire test\n    suite, and is compatible with ``xunit2`` JUnit family.\n\n    This is a ``session``-scoped fixture which is called with ``(name, value)``. Example:\n\n    .. code-block:: python\n\n        def test_foo(record_testsuite_property):\n            record_testsuite_property(\"ARCH\", \"PPC\")\n            record_testsuite_property(\"STORAGE_TYPE\", \"CEPH\")\n\n    :param name:","sourceCodeStart":319,"sourceCodeEnd":355,"githubUrl":"https://github.com/pytest-dev/pytest/blob/0d6fbdeffa57c796123f62f81f7dd370d9b7ecdc/src/_pytest/junitxml.py#L319-L355","documentation":"_check_record_param_type (junitxml.py:337) validates that the NAME argument passed to record_testsuite_property (and similarly record_property) is a str. If the caller passes a non-string name (int, tuple, etc.), it raises TypeError naming the bad type. The VALUE may be any object; only the name must be a string because it becomes an XML attribute/tag name.","triggerScenarios":"Calling record_testsuite_property(123, 'v') or record_testsuite_property(('a','b'), 'v'); passing a variable expected to be a string but holding an int; looping over keys without casting.","commonSituations":"Programmatically generating property names from counters/enums without str(); mixing up argument order (passing value first); refactoring that changes name type.","solutions":["Cast the name to str before calling: record_testsuite_property(str(name), value).","Ensure name values are string literals or string-typed variables.","Double-check argument order: (name, value)."],"exampleFix":"// before\nrecord_testsuite_property(run_id, 'passed')  # run_id is int\n// after\nrecord_testsuite_property(str(run_id), 'passed')","handlingStrategy":"type-guard","validationCode":"# Validate name is str before recording a property\ndef safe_suite_property(record_fn, name, value):\n    if not isinstance(name, str):\n        raise TypeError(f'name must be str, got {type(name).__name__}')\n    record_fn(name, value)","typeGuard":"def is_property_name(v) -> bool:\n    return isinstance(v, str) and v.isidentifier()","tryCatchPattern":null,"preventionTips":["Always cast names to str.","Use string literals or string-typed variables for property names.","Remember argument order: (name, value)."],"tags":["pytest","junitxml","type-check","reporting"],"backgroundTag":null,"analyzedSha":"0d6fbdeffa57c796123f62f81f7dd370d9b7ecdc","analyzedAt":"2026-08-11T20:52:36.969Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}