pytest-dev/pytest · error · UsageError

Expected a float string for option

Error message

Expected a float string for option {name} of type float, but got: {value!r}

What it means

Raised by _getini_ini() at config/__init__.py:1933-1936 when an ini option of type 'float' receives a value that is not a string. Like error 58, the function contract says INI-mode values are always str|list[str] (capture.py:1891-1895), so this is a defensive guard against pytest-internal bugs or direct injection into Config._inicfg. The outer handler at config/__init__.py:1847-1848 converts the TypeError to UsageError.

Solutions

  1. Confirm no plugin is injecting non-string values into Config._inicfg for float-typed options
  2. Provide the value as a string in the config file: faulthandler_timeout = 1.5
  3. Report upstream if reached through normal pyproject.toml/pytest.ini loading
Defensive patterns

Strategy: validation

Validate before calling

if not isinstance(value, str):
    value = str(value)

Type guard

def is_float_string(v) -> bool:
    if not isinstance(v, str):
        return False
    try:
        float(v); return True
    except ValueError:
        return False

Try / catch

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

Prevention

When it happens

Trigger: Only reachable through non-standard code paths - e.g. faulthandler_timeout (faulthandler.py:27, default=0.0 float) being injected with a non-string value via a monkeypatch or a buggy custom config loader. capture.py:1934 checks `not isinstance(value, str)` and raises.

Common situations: Should not occur in normal use. If you hit it, a plugin or test is writing directly to Config._inicfg or the toml/ini loaders have been customized.

Related errors


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

Appendix: source

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

            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,
        default: Any,
    ):
        """Handle TOML config values with strict type validation and no coercion.

        In TOML mode, values already have native types from TOML parsing.
        We validate types match expectations exactly, including list items.

View on GitHub (pinned to 0d6fbdeffa)