pytest-dev/pytest · error · UsageError

{path}: Cannot use both [pytest] and [tool.pytest]/[tool.pyt

Error message

{path}: Cannot use both [pytest] and [tool.pytest]/[tool.pytest.ini_options] in the same file. Please use [pytest], which is what pytest's own configuration files use; the [tool.pytest] tables are meant for pyproject.toml.

What it means

In a non-pyproject TOML file (e.g. pytest.toml), pytest accepts either the [pytest] table (its own native style) or the [tool.pytest]/[tool.pytest.ini_options] tables (the pyproject convention). Mixing both styles in one file is rejected because the precedence would be ambiguous and the [tool.*] tables are meant only for pyproject.toml.

Source

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


def _load_custom_toml(path: Path) -> ConfigDict | None:
    """Load a TOML file with an arbitrary name, as passed via ``-c``.

    Such a file reads its configuration from ``[pytest]``, like ``pytest.toml``
    does -- the table pytest documents for its own files (#14705). The
    ``pyproject.toml`` tables ``[tool.pytest]``/``[tool.pytest.ini_options]``,
    which arbitrary TOML files used to be parsed with exclusively, keep
    working; using both styles in one file is an error.
    """
    document = _parse_toml_file(path)

    tool_pytest_config = _config_from_tool_pytest(path, document)
    if tool_pytest_config is None:
        return _config_from_pytest_table(path, document)

    if "pytest" in document:
        raise UsageError(
            f"{path}: Cannot use both [pytest] and [tool.pytest]/"
            "[tool.pytest.ini_options] in the same file. Please use [pytest], "
            "which is what pytest's own configuration files use; the "
            "[tool.pytest] tables are meant for pyproject.toml."
        )
    return tool_pytest_config


def _load_pyproject_toml(path: Path) -> ConfigDict | None:
    """Load a ``pyproject.toml``-style file.

    Configuration is read from ``[tool.pytest]`` (TOML mode) or
    ``[tool.pytest.ini_options]`` (INI mode).
    """
    return _config_from_tool_pytest(path, _parse_toml_file(path))


#: Loaders for the config files pytest discovers by name, in precedence order.

View on GitHub (pinned to 0d6fbdeffa)

Solutions

  1. In pytest's own .toml files, keep only the [pytest] table and remove [tool.pytest] / [tool.pytest.ini_options].
  2. If you want the [tool.pytest] style, rename the file to pyproject.toml and remove the [pytest] table.

Example fix

// before
[pytest]
addopts = ["-ra"]

[tool.pytest.ini_options]
minversion = "7.0"
// after
[pytest]
addopts = ["-ra"]
minversion = "7.0"
Defensive patterns

Strategy: validation

Validate before calling

import tomllib, pathlib

def validate_pytest_toml_style(path: str) -> None:
    doc = tomllib.loads(pathlib.Path(path).read_text())
    has_pytest = 'pytest' in doc
    has_tool_pytest = 'pytest' in doc.get('tool', {})
    assert not (has_pytest and has_tool_pytest), \
        'mixing [pytest] and [tool.pytest] in one file is not allowed'

Type guard

null

Try / catch

null

Prevention

When it happens

Trigger: A pytest.toml containing both a [pytest] table and a [tool.pytest] (or [tool.pytest.ini_options]) table; copy-pasting a pyproject snippet into pytest.toml alongside an existing [pytest] block.

Common situations: Renaming pyproject.toml to pytest.toml without stripping the [tool.pytest] wrapper; merging configs from different projects.

Related errors


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