pytest-dev/pytest · error · UsageError

: config option ' ' expects a list for type 'paths', got

Error message

{self.inipath}: config option '{name}' expects a list for type 'paths', got {value_type}: {value!r}

What it means

Raised by pytest's TOML config parser (_getini_toml) when an ini option declared with type 'paths' is set to a non-list value in pyproject.toml or tox.ini. Unlike legacy ini parsing, TOML mode performs strict type validation with no coercion — the value must already be a native TOML array. The error includes the config file path, option name, actual type, and the offending value.

Solutions

  1. Wrap the value in square brackets in pyproject.toml: change `testpaths = "tests"` to `testpaths = ["tests"]`
  2. Verify the TOML file parses to a list by checking with a TOML parser or `python -c "import tomllib; print(tomllib.loads(open('pyproject.toml','rb').read())['tool']['pytest']['ini_options']['testpaths'])"`
  3. If you intentionally want a single path, still use a single-element list: testpaths = ["tests"]

Example fix

// pyproject.toml — before
[tool.pytest.ini_options]
testpaths = "tests"

// after
[tool.pytest.ini_options]
testpaths = ["tests"]
Defensive patterns

Strategy: validation

Validate before calling

# Before writing pyproject.toml, validate paths options parse as lists
import tomllib
with open('pyproject.toml', 'rb') as f:
    data = tomllib.load(f)
opts = data.get('tool', {}).get('pytest', {}).get('ini_options', {})
for key, val in opts.items():
    if isinstance(val, list):
        for item in val:
            if not isinstance(item, str):
                print(f"{key}: item {item!r} is not a string")
    elif key in ('testpaths', 'python_files', 'python_classes', 'python_functions'):
        print(f"{key}: expected a list, got {type(val).__name__}")

Type guard

def is_path_list(value: object) -> bool:
    return isinstance(value, list) and all(isinstance(item, str) for item in value)

Prevention

When it happens

Trigger: A plugin or pytest itself registers an ini option with addini(type='paths'). The user provides a scalar (e.g., a string or integer) instead of an inline array in the [tool.pytest.ini_options] section of pyproject.toml. Example: testpaths = "tests" instead of testpaths = ["tests"]. The check `isinstance(value, list)` fails and TypeError is raised.

Common situations: Migrating from pytest.ini (where bare strings are accepted for path options) to pyproject.toml without converting the value to a TOML array. Copying TOML snippets from outdated blog posts. Confusing TOML syntax (a quoted string is not an array).

Related errors


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

Appendix: source

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

    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.
        """
        value_type = builtins.type(value).__name__
        if type == "paths":
            # Expect a list of strings.
            if not isinstance(value, list):
                raise TypeError(
                    f"{self.inipath}: config option '{name}' expects a list for type 'paths', "
                    f"got {value_type}: {value!r}"
                )
            for i, item in enumerate(value):
                if not isinstance(item, str):
                    item_type = builtins.type(item).__name__
                    raise TypeError(
                        f"{self.inipath}: config option '{name}' expects a list of strings, "
                        f"but item at index {i} is {item_type}: {item!r}"
                    )
            dp = (
                self.inipath.parent
                if self.inipath is not None
                else self.invocation_params.dir
            )
            return [dp / x for x in value]
        elif type in {"args", "linelist"}:
            # Expect a list of strings.

View on GitHub (pinned to 0d6fbdeffa)