pytest-dev/pytest · error · UsageError

Expected an int string for option

Error message

Expected an int string for option {name} of type integer, but got: {value!r}

What it means

Raised by _getini_ini() at config/__init__.py:1927-1930 when an ini option of type 'int' receives a value that is not a string. The function comment at capture.py:1891-1895 states INI-mode values are always str or list[str], so this defensive TypeError is effectively unreachable through normal pytest usage - it guards against bugs in pytest itself or in code that monkeypatches the value pipeline. The outer handler at config/__init__.py:1847-1848 converts it to UsageError.

Solutions

  1. Confirm the option is declared with type='int' (or int) and you are not bypassing pytest's config loading
  2. If you have a custom plugin that writes to Config._inicfg, ensure values are strings in INI mode
  3. Report upstream if the value comes from a standard pyproject.toml/pytest.ini load - this branch should be unreachable
Defensive patterns

Strategy: validation

Validate before calling

# In INI mode ensure int-typed values are strings
if not isinstance(value, str):
    value = str(value)

Type guard

def is_int_string(v) -> bool:
    return isinstance(v, str) and v.lstrip('-').isdigit()

Try / catch

from _pytest.config import UsageError
try:
    val = config.getini('opt')
except UsageError as e:
    print(f'Internal: non-string reached int branch: {e}')

Prevention

When it happens

Trigger: Only reachable if a non-string value reaches _getini_ini for an int-typed option - e.g. a plugin monkeypatching _inicfg to inject a non-string, or an internal pytest bug. capture.py:1928 checks `not isinstance(value, str)` and raises.

Common situations: Effectively does not occur in normal pytest runs. If you see it, suspect a plugin that bypasses the normal config loading or a test harness that injects values directly into Config._inicfg.

Related errors


AI-assisted analysis of pytest-dev/pytest@0d6fbdeffa (2026-08-11). Data as JSON: /api/errors/b906fb7b9c89efd6. Report an issue: GitHub.

Appendix: source

Thrown at src/_pytest/config/__init__.py:1931

                if self.inipath is not None
                else self.invocation_params.dir
            )
            input_values = shlex.split(value) if isinstance(value, str) else value
            return [dp / x for x in input_values]
        elif type == "args":
            return shlex.split(value) if isinstance(value, str) else value
        elif type == "linelist":
            if isinstance(value, str):
                return [t for t in map(lambda x: x.strip(), value.split("\n")) if t]
            else:
                return value
        elif type == "bool":
            return _strtobool(str(value).strip())
        elif type == "string":
            return value
        elif type == "int":
            if not isinstance(value, str):
                raise TypeError(
                    f"Expected an int string for option {name} of type integer, but got: {value!r}"
                ) from None
            return int(value)
        elif type == "float":
            if not isinstance(value, str):
                raise TypeError(
                    f"Expected a float string for option {name} of type float, but got: {value!r}"
                ) from None
            return float(value)
        else:
            return self._getini_unknown_type(name, type, value)

    def _getini_toml(
        self,
        name: str,
        canonical_name: str,
        type: str,
        value: object,

View on GitHub (pinned to 0d6fbdeffa)