{"record":{"id":"4048d65d101874bb","repo":"pytest-dev/pytest","slug":"optname-must-be-a-directory-given-path","errorCode":null,"errorMessage":"{optname} must be a directory, given: {path}","messagePattern":"(.+?) must be a directory, given: (.+?)","errorType":"exception","errorClass":"UsageError","httpStatus":null,"severity":"error","filePath":"src/_pytest/config/__init__.py","lineNumber":308,"sourceCode":"def filename_arg(path: str, optname: str) -> str:\n    \"\"\"Argparse type validator for filename arguments.\n\n    :path: Path of filename.\n    :optname: Name of the option.\n    \"\"\"\n    if os.path.isdir(path):\n        raise UsageError(f\"{optname} must be a filename, given: {path}\")\n    return path\n\n\ndef directory_arg(path: str, optname: str) -> str:\n    \"\"\"Argparse type validator for directory arguments.\n\n    :path: Path of directory.\n    :optname: Name of the option.\n    \"\"\"\n    if not os.path.isdir(path):\n        raise UsageError(f\"{optname} must be a directory, given: {path}\")\n    return path\n\n\n# Plugins that cannot be disabled via \"-p no:X\" currently.\nessential_plugins = (\n    \"mark\",\n    \"main\",\n    \"runner\",\n    \"fixtures\",\n    \"helpconfig\",  # Provides -p.\n)\n\ndefault_plugins = (\n    *essential_plugins,\n    \"python\",\n    \"terminal\",\n    \"debugging\",\n    \"unittest\",","sourceCodeStart":290,"sourceCodeEnd":326,"githubUrl":"https://github.com/pytest-dev/pytest/blob/0d6fbdeffa57c796123f62f81f7dd370d9b7ecdc/src/_pytest/config/__init__.py#L290-L326","documentation":"Raised by directory_arg() (src/_pytest/config/__init__.py:301) when the supplied path is NOT a directory. directory_arg is the argparse type validator paired with filename_arg (config/__init__.py:290); options that need a directory use it. It raises UsageError when os.path.isdir(path) is False so the user gets a short message.","triggerScenarios":"Passing a file path or non-existent path to a CLI option whose argparse type is directory_arg (config/__init__.py:307-308). Common options include --rootdir and --basetemp.","commonSituations":"`pytest --rootdir=setup.py` (file, not dir); `pytest --basetemp=/tmp/does/not/exist`; mis-pasting a project file path where a directory was expected.","solutions":["Point the option at an existing directory (mkdir -p first if needed)","For --rootdir, point at the project root, not a source file inside it","Drop the option and let pytest infer the directory from the args"],"exampleFix":"// before\npytest --rootdir=src/app.py\n// after\npytest --rootdir=src","handlingStrategy":"validation","validationCode":"import os\nif not os.path.isdir(path):\n    raise ValueError(f'{optname} expects a directory, got {path}')","typeGuard":"def is_dir(p: str) -> bool:\n    import os\n    return os.path.isdir(p)","tryCatchPattern":"from _pytest.config import directory_arg\ntry:\n    p = directory_arg(user_input, 'opt')\nexcept UsageError as e:\n    print(e)","preventionTips":["mkdir -p directories before passing them to pytest options that expect dirs","Point --rootdir at project roots, not source files","Validate with os.path.isdir in wrapper scripts to give a clearer error than pytest's"],"tags":["cli","argparse","config","validation"],"backgroundTag":null,"analyzedSha":"0d6fbdeffa57c796123f62f81f7dd370d9b7ecdc","analyzedAt":"2026-08-11T20:52:36.969Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}