{"record":{"id":"3e61c7d1cdfac424","repo":"ungoogled-software/ungoogled-chromium","slug":"could-not-find-relative-to-directory-in-extracted","errorCode":null,"errorMessage":"Could not find relative_to directory in extracted files: %s","messagePattern":"Could not find relative_to directory in extracted files: (.+?)","errorType":"exception","errorClass":"FileNotFoundError","httpStatus":null,"severity":"error","filePath":"utils/_extraction.py","lineNumber":83,"sourceCode":"    if Path(extractor_cmd).is_file():\n        return extractor_cmd\n    return shutil.which(extractor_cmd)\n\n\ndef _process_relative_to(unpack_root, relative_to):\n    \"\"\"\n    For an extractor that doesn't support an automatic transform, move the extracted\n    contents from the relative_to/ directory to the unpack_root\n\n    If relative_to is None, nothing is done.\n    \"\"\"\n    if relative_to is None:\n        return\n    relative_root = unpack_root / relative_to\n    if not relative_root.is_dir():\n        get_logger().error('Could not find relative_to directory in extracted files: %s',\n                           relative_to)\n        raise FileNotFoundError()\n    for src_path in relative_root.iterdir():\n        dest_path = unpack_root / src_path.name\n        src_path.rename(dest_path)\n    relative_root.rmdir()\n\n\ndef _extract_tar_with_7z(binary, archive_path, output_dir, relative_to):\n    get_logger().debug('Using 7-zip extractor')\n    if not relative_to is None and (output_dir / relative_to).exists():\n        get_logger().error('Temporary unpacking directory already exists: %s',\n                           output_dir / relative_to)\n        raise FileExistsError()\n    cmd1 = (binary, 'x', str(archive_path), '-so')\n    cmd2 = (binary, 'x', '-si', '-snld', '-aoa', '-ttar', f'-o{str(output_dir)}')\n    get_logger().debug('7z command line: %s | %s', ' '.join(cmd1), ' '.join(cmd2))\n\n    proc1 = subprocess.Popen(cmd1, stdout=subprocess.PIPE) #pylint: disable=consider-using-with\n    proc2 = subprocess.Popen(cmd2, stdin=proc1.stdout, stdout=subprocess.PIPE) #pylint: disable=consider-using-with","sourceCodeStart":65,"sourceCodeEnd":101,"githubUrl":"https://github.com/ungoogled-software/ungoogled-chromium/blob/f85e84a480e2e17c103de7013de94320f9a2ba39/utils/_extraction.py#L65-L101","documentation":"Raised by _process_relative_to when a relative_to path is supplied but the corresponding directory does not exist inside the unpacked output after extraction. The library uses relative_to to hoist a nested directory (e.g. 'payload/bin') to the top level of output_dir; if the archive did not produce that directory, extraction is considered wrong and it aborts.","triggerScenarios":"Calling extract_tar_file / extract_with_7z / extract_with_winrar with a relative_to value naming a directory that is absent from the archive, misspelled, uses the wrong separator, or extraction failed silently leaving no such folder.","commonSituations":"Archives that changed layout between versions (inner folder renamed like 'chrome-linux' -> 'chrome-linux64'), typo in the relative_to string, passing a Windows-style path with backslashes, or the archive extracting as a single root directory the caller did not account for.","solutions":["List the archive contents (tar -tf / 7z l) and set relative_to to the exact inner directory path it contains","Verify extraction succeeded (returncode 0, files present in output_dir) before blaming relative_to","Ensure relative_to uses os-style forward slashes relative to the archive root","Pass relative_to=None if you do not need the nested directory hoisted"],"exampleFix":"// before\nextract_tar_file('chrome.tar.xz', out, relative_to='chrome-linux')\n// after (after inspecting: archive root is chrome-linux64)\nextract_tar_file('chrome.tar.xz', out, relative_to='chrome-linux64')","handlingStrategy":"validation","validationCode":"import tarfile\nnames = set().union(*[set(m.names) for m in [tarfile.open(archive)]]) if False else None\n# simpler: list archive dirs\nimport subprocess\nlisting = subprocess.run(['tar', '-tf', str(archive_path)], capture_output=True, text=True).stdout\ninner = {n.split('/')[0] for n in listing.splitlines() if n.strip()}\nassert relative_to in inner or any(n.startswith(relative_to + '/') for n in listing.splitlines()), f'{relative_to} not in archive'","typeGuard":"def has_relative_dir(unpack_root, relative_to):\n    from pathlib import Path\n    return relative_to is None or (Path(unpack_root) / relative_to).is_dir()","tryCatchPattern":"try:\n    extract_tar_file(archive, out, relative_to='chrome-linux')\nexcept FileNotFoundError:\n    logger.warning('relative_to missing in archive; inspecting layout')\n    # re-extract with corrected relative_to or None","preventionTips":["Inspect archive contents with tar -tf/7z l before choosing relative_to","Pin the upstream artifact version so its internal layout cannot change silently","Use forward-slash relative paths independent of host OS","Add an integration test asserting the expected inner directory exists after extraction"],"tags":["filesystem","archive-extraction","path-not-found"],"backgroundTag":"archive-relative-dir-missing","analyzedSha":"f85e84a480e2e17c103de7013de94320f9a2ba39","analyzedAt":"2026-08-29T10:07:17.606Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}