{"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":"exception","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/98b357f69e380da908740a212288d73b2ee06687/src/_pytest/junitxml.py#L319-L355","documentation":"Raised by `_check_record_param_type` (used by the `record_testsuite_property` fixture) when the property NAME passed in is not a string. The JUnit XML property name must be a string; passing an int/None/etc. triggers TypeError naming the parameter (\"name\") and the actual type. Note the explicit check runs in the no-xml branch; with --junitxml the underlying recorder applies its own conversion.","triggerScenarios":"Calling `record_testsuite_property(123, \"v\")` or `record_testsuite_property(None, \"v\")` from a test, where the first argument (name) is not a `str`.","commonSituations":"Programmatically building property names from computed values (ints/enums) without str() conversion. Passing a variable that is unexpectedly None.","solutions":["Coerce the name to str before calling: `record_testsuite_property(str(name), value)`.","Validate the name is a non-empty string before recording.","Use string literals or f-strings for property names."],"exampleFix":"// before\nrecord_testsuite_property(count, \"v\")  # count is int -> TypeError\n// after\nrecord_testsuite_property(str(count), \"v\")","handlingStrategy":"type-guard","validationCode":"def safe_record_property(record, name, value):\n    if not isinstance(name, str):\n        name = str(name)\n    record(name, value)","typeGuard":"def is_valid_property_name(name) -> bool:\n    return isinstance(name, str) and len(name) > 0","tryCatchPattern":null,"preventionTips":["Always pass a string literal or str(name) to record_testsuite_property.","Validate computed names before recording."],"tags":["pytest","junitxml","record-property","typeerror"],"analyzedSha":"98b357f69e380da908740a212288d73b2ee06687","analyzedAt":"2026-08-04T20:26:34.442Z","schemaVersion":2}