{"record":{"id":"0d4bb97c12d7d869","repo":"ungoogled-software/ungoogled-chromium","slug":"destination-already-exists-destination","errorCode":null,"errorMessage":"destination already exists: {destination}","messagePattern":"destination already exists: (.+?)","errorType":"exception","errorClass":"FileExistsError","httpStatus":null,"severity":"error","filePath":"utils/patches.py","lineNumber":173,"sourceCode":"\n\ndef merge_patches(source_iter, destination, prepend=False):\n    \"\"\"\n    Merges GNU quilt-formatted patches directories from sources into destination\n\n    destination must not already exist, unless prepend is True. If prepend is True, then\n    the source patches will be prepended to the destination.\n    \"\"\"\n    series = []\n    known_paths = set()\n    if destination.exists():\n        if prepend:\n            if not (destination / 'series').exists():\n                raise FileNotFoundError(\n                    f\"Could not find series file in existing destination: {destination / 'series'}\")\n            known_paths.update(generate_patches_from_series(destination))\n        else:\n            raise FileExistsError(f'destination already exists: {destination}')\n    for source_dir in source_iter:\n        patch_paths = tuple(generate_patches_from_series(source_dir))\n        patch_intersection = known_paths.intersection(patch_paths)\n        if patch_intersection:\n            raise FileExistsError(f'Patches from {source_dir} have conflicting paths '\n                                  f'with other sources: {patch_intersection}')\n        series.extend(patch_paths)\n        _copy_files(patch_paths, source_dir, destination)\n    if prepend and (destination / 'series').exists():\n        series.extend(generate_patches_from_series(destination))\n    with (destination / 'series').open('w') as series_file:\n        series_file.write('\\n'.join(map(str, series)))\n\n\ndef _apply_callback(args, parser_error):\n    logger = get_logger()\n    patch_bin_path = None\n    if args.patch_bin is not None:","sourceCodeStart":155,"sourceCodeEnd":191,"githubUrl":"https://github.com/ungoogled-software/ungoogled-chromium/blob/f85e84a480e2e17c103de7013de94320f9a2ba39/utils/patches.py#L155-L191","documentation":"merge_patches raises FileExistsError when the destination directory already exists and prepend is not set. The function only merges into a fresh (nonexistent) destination, or an existing one when explicitly prepending, to avoid silently overwriting an existing patch set.","triggerScenarios":"Calling merge_patches / merge_platform_patches with a `destination` path that already exists as a directory while prepend=False (default). Also occurs on repeated invocations of the same merge (e.g. _merge_callback reruns) without cleanup.","commonSituations":"Re-running a merge script after a previous successful run; destination collides with an existing platform patches directory; wrong destination constant; a build tool retrying the merge step.","solutions":["Delete or move the existing destination directory before merging","Pass prepend=True if you intend to merge into the existing destination","Point destination at a new, unique path for this merge","Make the merge idempotent: check destination.exists() and skip or clean up before calling"],"exampleFix":"# before\nmerge_patches(sources, dest)  # FileExistsError on rerun\n# after\nimport shutil\nif dest.exists():\n    shutil.rmtree(dest)\nmerge_patches(sources, dest)","handlingStrategy":"validation","validationCode":"from pathlib import Path\ndest = Path(destination)\nassert not dest.exists() or prepend, f'destination exists: {dest}; pass prepend=True or remove it'","typeGuard":"def destination_is_fresh(dest):\n    return not Path(dest).exists()","tryCatchPattern":"try:\n    merge_patches(sources, dest)\nexcept FileExistsError as e:\n    logger.warning('stale destination, recreating: %s', e)\n    shutil.rmtree(dest)\n    merge_patches(sources, dest)","preventionTips":["Use a clean temp directory as destination for each merge run","Decide explicitly between fresh merge and prepend; never rely on defaults blindly","Clean up destination in error/retry paths before re-invoking the merge"],"tags":["file-exists","patches","merge","destination-conflict"],"backgroundTag":"destination-already-exists","analyzedSha":"f85e84a480e2e17c103de7013de94320f9a2ba39","analyzedAt":"2026-08-29T10:07:17.606Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}