{"record":{"id":"989e7f3c0592c215","repo":"ungoogled-software/ungoogled-chromium","slug":"got-non-zero-exit-code-running-join-cmd","errorCode":null,"errorMessage":"Got non-zero exit code running \"{' '.join(cmd)}\"","messagePattern":"Got non-zero exit code running \"(.+?)\"","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"utils/patches.py","lineNumber":76,"sourceCode":"        patch_bin_path = _find_patch_from_which()\n    if not patch_bin_path:\n        raise ValueError('Could not find patch from PATCH_BIN env var or \"which patch\"')\n\n    if not patch_bin_path.exists():\n        raise ValueError(f'Could not find the patch binary: {patch_bin_path}')\n\n    # Ensure patch actually runs\n    cmd = [str(patch_bin_path), '--version']\n    result = subprocess.run(cmd,\n                            stdout=subprocess.PIPE,\n                            stderr=subprocess.PIPE,\n                            check=False,\n                            universal_newlines=True)\n    if result.returncode:\n        get_logger().error('\"%s\" returned non-zero exit code', ' '.join(cmd))\n        get_logger().error('stdout:\\n%s', result.stdout)\n        get_logger().error('stderr:\\n%s', result.stderr)\n        raise RuntimeError(f\"Got non-zero exit code running \\\"{' '.join(cmd)}\\\"\")\n\n    return patch_bin_path\n\n\ndef dry_run_check(patch_path, tree_path, patch_bin_path=None):\n    \"\"\"\n    Run patch --dry-run on a patch\n\n    tree_path is the pathlib.Path of the source tree to patch\n    patch_path is a pathlib.Path to check\n    reverse is whether the patches should be reversed\n    patch_bin_path is the pathlib.Path of the patch binary, or None to find it automatically\n        See find_and_check_patch() for logic to find \"patch\"\n\n    Returns the status code, stdout, and stderr of patch --dry-run\n    \"\"\"\n    cmd = [\n        str(find_and_check_patch(patch_bin_path)), '-p1', '--ignore-whitespace', '-i',","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/ungoogled-software/ungoogled-chromium/blob/f85e84a480e2e17c103de7013de94320f9a2ba39/utils/patches.py#L58-L94","documentation":"find_and_check_patch runs the external `patch` binary via subprocess and raises RuntimeError when it exits with a non-zero status. The library logs stdout/stderr first, so the RuntimeError wraps an underlying patch-tool failure (bad patch file, wrong tree, missing binary behavior differences). It indicates the patch command itself failed, not a Python-side bug.","triggerScenarios":"Calling find_and_check_patch (directly or via dry_run_check / apply_patches) when the `patch` command returns non-zero: patch file doesn't apply to the target tree, malformed/unified diff mismatch, patch already applied (reversed), or patch_bin_path points to a broken/nonexistent binary wrapper.","commonSituations":"Kernel/source tree updated so hunks no longer match; running apply_patches twice on the same tree; wrong tree_path passed; distro `patch` variant with different flags; dry-run check failing before real apply.","solutions":["Read the logged stdout/stderr above the traceback to see the actual `patch` failure reason","Re-run with a clean checkout of the target tree to undo partial application","Verify the patch file matches the tree version (regenerate or update the patch series)","Check patch_bin_path resolves to a working `patch` binary (e.g. `patch --version`)","Use dry_run_check first to catch apply failures before mutating the tree"],"exampleFix":"# before\napply_patches(tree, patches)  # may raise RuntimeError mid-apply\n# after\ndry_run_check(tree, patches)  # validate first\napply_patches(tree, patches)","handlingStrategy":"try-catch","validationCode":"import shutil\nfrom utils.patches import dry_run_check\nif shutil.which(patch_bin_path or 'patch') is None:\n    raise SystemExit('patch binary not available')\ndry_run_check(patch_path, tree_path, patch_bin_path)  # fail before mutating","typeGuard":"def patch_binary_available(path):\n    return isinstance(path, (str, type(None))) and (path is None or shutil.which(path) is not None)","tryCatchPattern":"try:\n    apply_patches(tree, patches)\nexcept RuntimeError as e:\n    logger.exception('patch command failed: %s', e)\n    restore_clean_tree(tree)  # e.g. git checkout / re-extract","preventionTips":["Always dry_run_check before applying","Apply patches only to a pristine tree matching the patch base version","Never apply the same patch series twice to one tree","Pin/verify the `patch` binary in CI before running merges"],"tags":["subprocess","patch","runtime-error","external-tool"],"backgroundTag":"subprocess-nonzero-exit","analyzedSha":"f85e84a480e2e17c103de7013de94320f9a2ba39","analyzedAt":"2026-08-29T10:07:17.606Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}