{"id":"60ea4c436ba03cdb","repo":"pytest-dev/pytest","slug":"filepath-cannot-use-both-tool-pytest-native","errorCode":null,"errorMessage":"{filepath}: Cannot use both [tool.pytest] (native TOML types) and [tool.pytest.ini_options] (string-based INI format) simultaneously. Please use [tool.pytest] with native TOML types (recommended) or [tool.pytest.ini_options] for backwards compatibility.","messagePattern":"(.+?): Cannot use both \\[tool\\.pytest\\] \\(native TOML types\\) and \\[tool\\.pytest\\.ini_options\\] \\(string-based INI format\\) simultaneously\\. Please use \\[tool\\.pytest\\] with native TOML types \\(recommended\\) or \\[tool\\.pytest\\.ini_options\\] for backwards compatibility\\.","errorType":"exception","errorClass":"UsageError","httpStatus":null,"severity":"error","filePath":"src/_pytest/config/findpaths.py","lineNumber":138,"sourceCode":"                raise UsageError(\n                    f\"{filepath}: pytest configuration must be under a \"\n                    f\"[pytest] table (found top-level options: \"\n                    f\"{', '.join(top_level_options)})\"\n                )\n            # \"pytest.toml\" files are always the source of configuration, even if empty.\n            return {}\n\n        # pyproject.toml uses [tool.pytest] or [tool.pytest.ini_options].\n        else:\n            tool_pytest = config.get(\"tool\", {}).get(\"pytest\", {})\n\n            # Check for toml mode config: [tool.pytest] with content outside of ini_options.\n            toml_config = {k: v for k, v in tool_pytest.items() if k != \"ini_options\"}\n            # Check for ini mode config: [tool.pytest.ini_options].\n            ini_config = tool_pytest.get(\"ini_options\", None)\n\n            if toml_config and ini_config:\n                raise UsageError(\n                    f\"{filepath}: Cannot use both [tool.pytest] (native TOML types) and \"\n                    \"[tool.pytest.ini_options] (string-based INI format) simultaneously. \"\n                    \"Please use [tool.pytest] with native TOML types (recommended) \"\n                    \"or [tool.pytest.ini_options] for backwards compatibility.\"\n                )\n\n            if toml_config:\n                # TOML mode - preserve native TOML types.\n                return {\n                    k: ConfigValue(v, origin=\"file\", mode=\"toml\")\n                    for k, v in toml_config.items()\n                }\n\n            elif ini_config is not None:\n                # INI mode - TOML supports richer data types than INI files, but we need to\n                # convert all scalar values to str for compatibility with the INI system.\n                def make_scalar(v: object) -> str | list[str]:\n                    return v if isinstance(v, list) else str(v)","sourceCodeStart":120,"sourceCodeEnd":156,"githubUrl":"https://github.com/pytest-dev/pytest/blob/98b357f69e380da908740a212288d73b2ee06687/src/_pytest/config/findpaths.py#L120-L156","documentation":"Raised when a pyproject.toml contains BOTH a [tool.pytest] table (native TOML types, the newer recommended mode) AND a [tool.pytest.ini_options] table (legacy string-based INI mode). pytest cannot merge the two semantics, so it refuses to load and asks the user to pick one mode.","triggerScenarios":"A pyproject.toml with both [tool.pytest] keys (e.g. addopts directly) and a [tool.pytest.ini_options] subsection. The check at line 133-143 detects both toml_config (keys under [tool.pytest] excluding ini_options) and ini_config (the ini_options subtable).","commonSituations":"Partially migrating from [tool.pytest.ini_options] to [tool.pytest] and leaving remnants of both; merging config snippets from different sources/tutorials; copy-pasting a modern example while keeping old ini_options keys.","solutions":["Consolidate into [tool.pytest] (native TOML types, recommended): move all keys out of ini_options into [tool.pytest] directly and delete the [tool.pytest.ini_options] table.","Or keep [tool.pytest.ini_options] only for backwards compatibility and remove the [tool.pytest] table.","Re-run pytest after editing to confirm the conflict is resolved."],"exampleFix":"# before\n[tool.pytest]\naddopts = '-v'\n\n[tool.pytest.ini_options]\ntestpaths = ['tests']\n\n# after (native TOML mode)\n[tool.pytest]\naddopts = '-v'\ntestpaths = ['tests']","handlingStrategy":"validation","validationCode":"import sys, pathlib\ntry:\n    import tomllib\nexcept ImportError:\n    import tomli as tomllib\n\ndef validate_no_dual_pytest_tables(path: pathlib.Path) -> None:\n    config = tomllib.loads(path.read_text(encoding='utf-8'))\n    tool_pytest = config.get('tool', {}).get('pytest', {})\n    toml_keys = {k: v for k, v in tool_pytest.items() if k != 'ini_options'}\n    has_ini = 'ini_options' in tool_pytest\n    if toml_keys and has_ini:\n        raise ValueError(f'{path}: cannot use both [tool.pytest] and [tool.pytest.ini_options]')","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Choose one config mode ([tool.pytest] recommended) and delete the other during migration.","Review pyproject.toml after merging config snippets from external sources.","Add a CI lint that rejects simultaneous presence of both tables."],"tags":["pytest","config","toml","pyproject","config-structure","migration","usage-error"],"analyzedSha":"98b357f69e380da908740a212288d73b2ee06687","analyzedAt":"2026-08-04T20:26:34.442Z","schemaVersion":2}