{"id":"1bbf792074655909","repo":"pypa/pip","slug":"paths-must-be-relative","errorCode":null,"errorMessage":"paths must be relative","messagePattern":"paths must be relative","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/pip/_vendor/pyproject_hooks/_impl.py","lineNumber":111,"sourceCode":"    This uses :func:`subprocess.check_output` under the hood.\n    \"\"\"\n    env = os.environ.copy()\n    if extra_environ:\n        env.update(extra_environ)\n\n    check_output(cmd, cwd=cwd, env=env, stderr=STDOUT)\n\n\ndef norm_and_check(source_tree: str, requested: str) -> str:\n    \"\"\"Normalise and check a backend path.\n\n    Ensure that the requested backend path is specified as a relative path,\n    and resolves to a location under the given source tree.\n\n    Return an absolute version of the requested path.\n    \"\"\"\n    if os.path.isabs(requested):\n        raise ValueError(\"paths must be relative\")\n\n    abs_source = os.path.abspath(source_tree)\n    abs_requested = os.path.normpath(os.path.join(abs_source, requested))\n    # We have to use commonprefix for Python 2.7 compatibility. So we\n    # normalise case to avoid problems because commonprefix is a character\n    # based comparison :-(\n    norm_source = os.path.normcase(abs_source)\n    norm_requested = os.path.normcase(abs_requested)\n    if os.path.commonprefix([norm_source, norm_requested]) != norm_source:\n        raise ValueError(\"paths must be inside source tree\")\n\n    return abs_requested\n\n\nclass BuildBackendHookCaller:\n    \"\"\"A wrapper to call the build backend hooks for a source directory.\"\"\"\n\n    def __init__(","sourceCodeStart":93,"sourceCodeEnd":129,"githubUrl":"https://github.com/pypa/pip/blob/d7d0d0a39494e28ec1c407bd0680e4a4d1067791/src/pip/_vendor/pyproject_hooks/_impl.py#L93-L129","documentation":"pyproject_hooks' norm_and_check raises ValueError('paths must be relative') when a backend-path entry in pyproject.toml [build-system] is an absolute path. PEP 517 requires backend-path entries to be relative so the backend is loaded from within the project source tree.","triggerScenarios":"Constructing BuildBackendHookCaller with backend_path containing an absolute path (os.path.isabs(requested) is True), which happens when pyproject.toml lists absolute directories under [build-system] backend-path, e.g. backend-path = ['/abs/repo/backend'].","commonSituations":"Hand-editing pyproject.toml to point at an absolute backend location; build tools that resolve paths to absolute before passing them; Windows paths like 'C:\\\\backends\\\\x' that are inherently absolute.","solutions":["Change the backend-path entry in pyproject.toml to a path relative to the project root (where pyproject.toml lives).","If a tool is absolutizing the path, pass the source_dir correctly so a relative entry resolves properly.","Move the backend code under the source tree and reference it relatively."],"exampleFix":"# before\n[build-system]\nbuild-backend = \"my_backend\"\nbackend-path = [\"/home/user/proj/my_backend\"]\n\n# after\n[build-system]\nbuild-backend = \"my_backend\"\nbackend-path = [\"my_backend\"]","handlingStrategy":"validation","validationCode":"import os\nfor p in backend_paths:\n    if os.path.isabs(p):\n        raise ValueError(f'backend-path must be relative: {p!r}')","typeGuard":"def is_relative_path(p: str) -> bool:\n    return isinstance(p, str) and not os.path.isabs(p)","tryCatchPattern":"from pip._vendor.pyproject_hooks._impl import BuildBackendHookCaller\ntry:\n    caller = BuildBackendHookCaller(src, backend, backend_path=paths)\nexcept ValueError:\n    paths = [os.path.relpath(p, src) for p in paths]\n    caller = BuildBackendHookCaller(src, backend, backend_path=paths)","preventionTips":["Keep backend-path entries relative in pyproject.toml.","Validate paths with os.path.isabs before constructing the hook caller."],"tags":["pyproject-hooks","pep517","config","build"],"analyzedSha":"d7d0d0a39494e28ec1c407bd0680e4a4d1067791","analyzedAt":"2026-08-04T20:55:04.259Z","schemaVersion":2}