pytest-dev/pytest · error · UsageError

{filepath}: pytest configuration must be under a [pytest] ta

Error message

{filepath}: pytest configuration must be under a [pytest] table (found top-level options: {top_level_options})

What it means

Raised when a pytest.toml or .pytest.toml file contains configuration keys at the top level of the TOML document instead of nested under a [pytest] table. pytest.toml requires all configuration to live under [pytest]; stray top-level scalars/arrays are rejected to prevent silent misconfiguration.

Source

Thrown at src/_pytest/config/findpaths.py:120

        toml_text = filepath.read_text(encoding="utf-8")
        try:
            config = tomllib.loads(toml_text)
        except tomllib.TOMLDecodeError as exc:
            raise UsageError(f"{filepath}: {exc}") from exc

        # pytest.toml and .pytest.toml use [pytest] table directly.
        if filepath.name in ("pytest.toml", ".pytest.toml"):
            if "pytest" in config:
                # TOML mode - preserve native TOML types.
                return {
                    k: ConfigValue(v, origin="file", mode="toml")
                    for k, v in config["pytest"].items()
                }
            top_level_options = [
                key for key, value in config.items() if not isinstance(value, dict)
            ]
            if top_level_options:
                raise UsageError(
                    f"{filepath}: pytest configuration must be under a "
                    f"[pytest] table (found top-level options: "
                    f"{', '.join(top_level_options)})"
                )
            # "pytest.toml" files are always the source of configuration, even if empty.
            return {}

        # pyproject.toml uses [tool.pytest] or [tool.pytest.ini_options].
        else:
            tool_pytest = config.get("tool", {}).get("pytest", {})

            # Check for toml mode config: [tool.pytest] with content outside of ini_options.
            toml_config = {k: v for k, v in tool_pytest.items() if k != "ini_options"}
            # Check for ini mode config: [tool.pytest.ini_options].
            ini_config = tool_pytest.get("ini_options", None)

            if toml_config and ini_config:
                raise UsageError(

View on GitHub (pinned to 98b357f69e)

Solutions

  1. Wrap all pytest configuration under a [pytest] table in pytest.toml.
  2. Move non-pytest configuration out of pytest.toml into pyproject.toml or another file.

Example fix

# before (pytest.toml)
addopts = '-v'
testpaths = ['tests']

# after
[pytest]
addopts = '-v'
testpaths = ['tests']
Defensive patterns

Strategy: validation

Validate before calling

import sys, pathlib
try:
    import tomllib
except ImportError:
    import tomli as tomllib

def validate_pytest_toml(path: pathlib.Path) -> None:
    config = tomllib.loads(path.read_text(encoding='utf-8'))
    top_level = [k for k, v in config.items() if not isinstance(v, dict)]
    if top_level:
        raise ValueError(f'{path}: pytest config must be under [pytest]; found top-level: {top_level}')
    if 'pytest' not in config:
        raise ValueError(f'{path}: missing [pytest] table')

Prevention

When it happens

Trigger: A pytest.toml file like `addopts = '-v'` at the top level (no [pytest] header), or mixing tooling config at the top level with pytest config. The check at line 116-124 collects top-level non-dict keys and reports them.

Common situations: Migrating from pytest.ini (which uses a flat [pytest] section) to pytest.toml and forgetting to add the [pytest] table header; confusing pytest.toml semantics with pyproject.toml's [tool.pytest] nesting.

Related errors


AI-assisted analysis of pytest-dev/pytest@98b357f69e (2026-08-04). Data as JSON: /data/errors/243cb132c1850308.json. Report an issue: GitHub.