pytest-dev/pytest · error · TypeError
Expected id to be a string or a `pytest.HIDDEN_PARAM` sentin
Error message
Expected id to be a string or a `pytest.HIDDEN_PARAM` sentinel, got {type(id)}: {id!r} What it means
`ParameterSet.param(..., id=...)` validates that `id` is either a `str`, `None`, or the internal `pytest.HIDDEN_PARAM` sentinel. Anything else (int, bool, float, list) raises TypeError. The id becomes the test node id suffix and must be a string.
Source
Thrown at src/_pytest/mark/structures.py:134
def param(
cls,
*values: object,
marks: MarkDecorator | Collection[MarkDecorator | Mark] = (),
id: str | _HiddenParam | None = None,
) -> ParameterSet:
if isinstance(marks, MarkDecorator):
marks = (marks,)
else:
assert isinstance(marks, collections.abc.Collection)
if any(i.name == "usefixtures" for i in marks):
raise ValueError(
"pytest.param cannot add pytest.mark.usefixtures; see "
"https://docs.pytest.org/en/stable/reference/reference.html#pytest-param"
)
if id is not None:
if not isinstance(id, str) and id is not HIDDEN_PARAM:
raise TypeError(
"Expected id to be a string or a `pytest.HIDDEN_PARAM` sentinel, "
f"got {type(id)}: {id!r}",
)
return cls(values, marks, id)
@classmethod
def extract_from(
cls,
parameterset: ParameterSet | Sequence[object] | object,
force_tuple: bool = False,
) -> ParameterSet:
"""Extract from an object or objects.
:param parameterset:
A legacy style parameterset that may or may not be a tuple,
and may or may not be wrapped into a mess of mark objects.
:param force_tuple:View on GitHub (pinned to 98b357f69e)
Solutions
- Convert the id to `str`: `pytest.param(v, id=str(my_id))`.
- Pass `id=None` to let pytest auto-generate the id from the value.
- Use the `ids=` callable form of parametrize to map values to string ids centrally.
Example fix
# before pytest.param(user.id, id=user.id) # user.id is int # after pytest.param(user.id, id=str(user.id))
Defensive patterns
Strategy: type-guard
Validate before calling
def coerce_id(id):
return id if isinstance(id, str) or id is None else str(id) Type guard
def is_valid_param_id(id: object) -> bool:
return id is None or isinstance(id, str) Prevention
- Always stringify non-string ids.
- Prefer the `ids=` callable to centralize id generation.
When it happens
Trigger: `pytest.param(1, id=5)`, `pytest.param(1, id=True)`, or passing an enum/object as id.
Common situations: Using the loop counter or a database id (int) as the param id; forgetting to stringify.
Related errors
- Empty parameter set in '{func.__name__}' at line {lineno + 1
- pytest.param cannot add pytest.mark.usefixtures; see https:/
- got {mark_obj!r} instead of Mark
- must be absolute import path string, not {import_path!r}
- use setattr(target, name, value) or setattr(target, value) w
AI-assisted analysis of pytest-dev/pytest@98b357f69e (2026-08-04).
Data as JSON: /data/errors/29a707b4bf4fb156.json.
Report an issue: GitHub.