{"id":"c749583ea2094256","repo":"pypa/pip","slug":"path-s-cannot-be-absolute","errorCode":null,"errorMessage":"path '%s' cannot be absolute","messagePattern":"path '(.+?)' cannot be absolute","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/pip/_vendor/distlib/util.py","lineNumber":474,"sourceCode":"        return value\n\n\ndef convert_path(pathname):\n    \"\"\"Return 'pathname' as a name that will work on the native filesystem.\n\n    The path is split on '/' and put back together again using the current\n    directory separator.  Needed because filenames in the setup script are\n    always supplied in Unix style, and have to be converted to the local\n    convention before we can actually use them in the filesystem.  Raises\n    ValueError on non-Unix-ish systems if 'pathname' either starts or\n    ends with a slash.\n    \"\"\"\n    if os.sep == '/':\n        return pathname\n    if not pathname:\n        return pathname\n    if pathname[0] == '/':\n        raise ValueError(\"path '%s' cannot be absolute\" % pathname)\n    if pathname[-1] == '/':\n        raise ValueError(\"path '%s' cannot end with '/'\" % pathname)\n\n    paths = pathname.split('/')\n    while os.curdir in paths:\n        paths.remove(os.curdir)\n    if not paths:\n        return os.curdir\n    return os.path.join(*paths)\n\n\nclass FileOperator(object):\n\n    def __init__(self, dry_run=False):\n        self.dry_run = dry_run\n        self.ensured = set()\n        self._init_record()\n","sourceCodeStart":456,"sourceCodeEnd":492,"githubUrl":"https://github.com/pypa/pip/blob/d7d0d0a39494e28ec1c407bd0680e4a4d1067791/src/pip/_vendor/distlib/util.py#L456-L492","documentation":"Raised by convert_path() on non-Unix-like systems (where os.sep != '/', e.g. Windows). setup-script filenames are always supplied Unix-style and split on '/', but an absolute path (leading '/') cannot be meaningfully converted to a native path, so a ValueError is raised. On Unix (os.sep == '/') the function returns early and never raises this.","triggerScenarios":"Calling convert_path('/abs/path/to/file') on Windows, or distutils/setuptools setup() receiving a script/data_file path beginning with '/' while running on Windows.","commonSituations":"Cross-platform builds where a Linux developer hardcodes an absolute path in setup.py and a Windows CI worker runs the build; packaging scripts that compute paths from os.path.abspath and feed them to convert_path.","solutions":["Pass a relative path: convert_path('src/pkg/file.py') instead of '/src/pkg/file.py'.","On Windows, rebuild the path relative to the project root before calling convert_path.","Avoid feeding os.path.abspath() output into convert_path()."],"exampleFix":"// before\nconvert_path('/src/mypkg/__init__.py')  # on Windows\n// after\nconvert_path('src/mypkg/__init__.py')","handlingStrategy":"validation","validationCode":"import os\ndef safe_convert_path(p):\n    if os.sep != '/' and p.startswith('/'):\n        raise ValueError('convert_path received absolute path: %r' % p)\n    from distlib.util import convert_path\n    return convert_path(p)","typeGuard":null,"tryCatchPattern":"from distlib.util import convert_path\ntry:\n    native = convert_path(script_path)\nexcept ValueError as e:\n    if 'cannot be absolute' in str(e):\n        native = convert_path(os.path.relpath(script_path, project_root))\n    else:\n        raise","preventionTips":["Never pass os.path.abspath() output to convert_path().","Always use project-relative paths in setup() script/data_file lists.","Test packaging builds on Windows CI, not just Linux."],"tags":["path","filesystem","windows","cross-platform","packaging"],"analyzedSha":"d7d0d0a39494e28ec1c407bd0680e4a4d1067791","analyzedAt":"2026-08-04T20:55:04.259Z","schemaVersion":2}