{"id":"40965fc59199edd1","repo":"python-poetry/poetry","slug":"root-is-not-a-valid-repository-cache","errorCode":null,"errorMessage":"{root} is not a valid repository cache","messagePattern":"(.+?) is not a valid repository cache","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/poetry/console/commands/cache/clear.py","lineNumber":49,"sourceCode":"    ]\n\n    def handle(self) -> int:\n        cache = self.argument(\"cache\")\n\n        if cache:\n            parts = cache.split(\":\")\n            root = parts[0]\n        else:\n            parts = []\n            root = \"\"\n\n        config = Config.create()\n        cache_dir = config.repository_cache_directory / root\n\n        try:\n            cache_dir.relative_to(config.repository_cache_directory)\n        except ValueError:\n            raise ValueError(f\"{root} is not a valid repository cache\")\n\n        cache = FileCache(cache_dir)\n\n        if len(parts) < 2:\n            if not self.option(\"all\"):\n                raise RuntimeError(\n                    \"Add the --all option if you want to clear all cache entries\"\n                )\n\n            if not cache_dir.exists():\n                self.line(\n                    f\"No cache entries for {root}\" if root else \"No cache entries\"\n                )\n                return 0\n\n            # Calculate number of entries\n            entries_count = sum(\n                len(files) for _path, _dirs, files in os.walk(str(cache_dir))","sourceCodeStart":31,"sourceCodeEnd":67,"githubUrl":"https://github.com/python-poetry/poetry/blob/92b74dcfe348d0e01e14d40d6c1fa47a4ee04a54/src/poetry/console/commands/cache/clear.py#L31-L67","documentation":"Raises ValueError in CacheClearCommand.handle() when the first segment of the cache argument (the 'root') resolves to a path that is not relative to the repository_cache_directory. This is a path-traversal guard: Path.relative_to() raises ValueError if the cache_dir is not under repository_cache_directory, and Poetry re-raises with a clear message naming the offending root.","triggerScenarios":"Running `poetry cache clear ../foo` or any cache argument whose first colon-separated segment contains path traversal characters (.., /, etc.) that escape the repository cache directory. The check is cache_dir.relative_to(config.repository_cache_directory).","commonSituations":"User passes a filesystem path instead of a cache name, uses '..' segments, or the cache name contains slashes that resolve outside the cache root.","solutions":["Use a valid cache root name without path separators or '..' segments — typically a repository/source name like 'pypi'.","Use `poetry cache clear --all` to clear the entire cache without specifying a root."],"exampleFix":"# before (error)\npoetry cache clear ../something\n# after\npoetry cache clear pypi:requests:2.28.0\n# or clear everything\npoetry cache clear --all","handlingStrategy":"validation","validationCode":"from pathlib import Path\n\ndef validate_cache_root(root: str, repository_cache_dir: Path) -> None:\n    cache_dir = repository_cache_dir / root\n    cache_dir.relative_to(repository_cache_dir)  # raises ValueError if traversal","typeGuard":"from pathlib import Path\n\ndef is_valid_cache_root(root: str, repository_cache_dir: Path) -> bool:\n    try:\n        (repository_cache_dir / root).relative_to(repository_cache_dir)\n        return True\n    except ValueError:\n        return False","tryCatchPattern":null,"preventionTips":["Use plain repository/source names (e.g. 'pypi') as cache roots, not filesystem paths.","Avoid '..', '/', and other path separators in cache arguments.","Use 'poetry cache clear --all' to clear everything without targeting a specific root."],"tags":["cache-command","path-traversal","security","valueerror"],"analyzedSha":"92b74dcfe348d0e01e14d40d6c1fa47a4ee04a54","analyzedAt":"2026-08-04T20:33:34.072Z","schemaVersion":2}