{"id":"a4445e448418a27c","repo":"pypa/pip","slug":"path-is-a-symlink-will-not-return-uid-for-symli","errorCode":null,"errorMessage":"{path} is a symlink; Will not return uid for symlinks","messagePattern":"(.+?) is a symlink; Will not return uid for symlinks","errorType":"exception","errorClass":"OSError","httpStatus":null,"severity":"warning","filePath":"src/pip/_internal/utils/compat.py","lineNumber":66,"sourceCode":"        https://github.com/pypa/pip/pull/935#discussion_r5307003\n\n    Placed this function in compat due to differences on AIX and\n    Jython, that should eventually go away.\n\n    :raises OSError: When path is a symlink or can't be read.\n    \"\"\"\n    if hasattr(os, \"O_NOFOLLOW\"):\n        fd = os.open(path, os.O_RDONLY | os.O_NOFOLLOW)\n        file_uid = os.fstat(fd).st_uid\n        os.close(fd)\n    else:  # AIX and Jython\n        # WARNING: time of check vulnerability, but best we can do w/o NOFOLLOW\n        if not os.path.islink(path):\n            # older versions of Jython don't have `os.fstat`\n            file_uid = os.stat(path).st_uid\n        else:\n            # raise OSError for parity with os.O_NOFOLLOW above\n            raise OSError(f\"{path} is a symlink; Will not return uid for symlinks\")\n    return file_uid\n\n\n# The importlib.resources.open_text function was deprecated in 3.11 with suggested\n# replacement we use below.\nif sys.version_info < (3, 11):\n    open_text_resource = importlib.resources.open_text\nelse:\n\n    def open_text_resource(\n        package: str, resource: str, encoding: str = \"utf-8\", errors: str = \"strict\"\n    ) -> IO[str]:\n        return (importlib.resources.files(package) / resource).open(\n            \"r\", encoding=encoding, errors=errors\n        )\n\n\nif sys.version_info >= (3, 11):","sourceCodeStart":48,"sourceCodeEnd":84,"githubUrl":"https://github.com/pypa/pip/blob/d7d0d0a39494e28ec1c407bd0680e4a4d1067791/src/pip/_internal/utils/compat.py#L48-L84","documentation":"get_path_uid raises OSError (on platforms lacking os.O_NOFOLLOW — AIX and Jython) when the path being checked is a symlink. The function deliberately refuses to follow symlinks so that a symlinked cache dir cannot be used to trick pip's ownership check. On platforms with O_NOFOLLOW the open() itself fails instead.","triggerScenarios":"hasattr(os,'O_NOFOLLOW') is False (AIX/Jython) and os.path.islink(path) is True. Called from cache-dir/user-site ownership validation when that directory (or a parent) is a symlink.","commonSituations":"Symlinking $XDG_CACHE_HOME/pip or a virtualenv's cache to another volume on AIX; Jython users; docker images that symlink /root/.cache. On mainstream Linux/macOS/Windows this branch is unreachable.","solutions":["Replace the symlinked cache/site directory with a real directory (copy contents, remove symlink).","Point PIP_CACHE_DIR / the relevant path at a non-symlink directory.","If a symlink is unavoidable on AIX/Jython, use a platform with O_NOFOLLOW (standard CPython on Linux/macOS/BSD)."],"exampleFix":"# before - $XDG_CACHE_HOME/pip is a symlink on AIX/Jython\nln -s /mnt/bigcache/pip ~/.cache/pip\npip install pkg\n\n# after - use a real directory\nrm ~/.cache/pip\nmkdir -p /mnt/bigcache/pip\nexport PIP_CACHE_DIR=/mnt/bigcache/pip\npip install pkg","handlingStrategy":"validation","validationCode":"import os\n\ndef ensure_real_cache_dir(cache_dir):\n    if os.path.islink(cache_dir):\n        raise SystemExit(\n            f\"refusing to use symlinked cache dir {cache_dir}; use a real directory\"\n        )\n# call at startup on platforms that may lack os.O_NOFOLLOW (AIX/Jython)","typeGuard":null,"tryCatchPattern":"try:\n    get_path_uid(cache_dir)\nexcept OSError as e:\n    if 'symlink' in str(e):\n        cache_dir = realpath_nonsymlink(cache_dir)\n    else:\n        raise","preventionTips":["Point PIP_CACHE_DIR at a real directory, not a symlink.","On AIX/Jython, prefer standard CPython which has O_NOFOLLOW.","Avoid symlinking venv/cache dirs across volumes."],"tags":["pip","filesystem","symlink","security","aix","jython","cache"],"analyzedSha":"d7d0d0a39494e28ec1c407bd0680e4a4d1067791","analyzedAt":"2026-08-04T20:55:04.259Z","schemaVersion":2}