dotnet/runtime · error · RuntimeError

Couldn't create git diff

Error message

Couldn't create git diff

What it means

Raised during assembly-diff generation when the subprocess 'git diff --output=<asm_diffs.diff> --no-index -- <base_asm_location> <diff_asm_location>' returns a code that is neither 0 (identical) nor 1 (differences found). git uses exit codes 0/1 for normal diff results, so any other code indicates git itself failed (e.g. missing input path, git not installed, permission error). The diff file that documents textual asm differences cannot be produced.

Solutions

  1. Run the git diff command printed in the debug log manually to see git's real stderr message.
  2. Verify both base_asm_location and diff_asm_location exist and contain .dasm files before enabling --git_diff.
  3. Ensure git is installed and on PATH (git --version succeeds) in the execution environment.
  4. Confirm the output path asm_diffs_location is in a writable directory.

Example fix

// before
git_diff_command = ["git", "diff", "--output=" + asm_diffs_location, "--no-index", "--", base_asm_location, diff_asm_location]
git_diff_proc = subprocess.Popen(git_diff_command, stdout=subprocess.PIPE)
git_diff_proc.communicate()
if git_diff_proc.returncode not in (0, 1):
    raise RuntimeError("Couldn't create git diff")
// after
git_diff_proc = subprocess.Popen(git_diff_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
_, stderr = git_diff_proc.communicate()
if git_diff_proc.returncode not in (0, 1):
    raise RuntimeError(f"git diff failed (code {git_diff_proc.returncode}): {stderr.decode('utf-8', 'replace').strip()}")
Defensive patterns

Strategy: validation

Validate before calling

import os, shutil, subprocess
def preflight_git_diff(base_asm_location, diff_asm_location, asm_diffs_location):
    import shutil as _s
    if shutil.which('git') is None:
        raise RuntimeError('git not found on PATH')
    for p in (base_asm_location, diff_asm_location):
        if not os.path.isdir(p):
            raise RuntimeError(f'asm location is not a directory: {p}')
    out_dir = os.path.dirname(asm_diffs_location)
    if not os.path.isdir(out_dir) or not os.access(out_dir, os.W_OK):
        raise RuntimeError(f'output dir missing or not writable: {out_dir}')

Try / catch

git_diff_proc = subprocess.Popen(git_diff_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
_, stderr = git_diff_proc.communicate()
if git_diff_proc.returncode not in (0, 1):
    raise RuntimeError(f"git diff failed (code {git_diff_proc.returncode}): {stderr.decode('utf-8', 'replace').strip()}")

Prevention

When it happens

Trigger: Triggered in the asm-diff branch when coreclr_args.git_diff is True: subprocess.Popen runs git diff --no-index on two assembly output directories; git_diff_proc.returncode is not in {0,1}. This occurs when one of the asm locations does not exist, when git is not on PATH, when paths contain characters git rejects, or when the --output target directory is unwritable.

Common situations: Running 'superpmi.py asmdiff' after a partial run where one side produced no .dasm files; git not installed or not on PATH in a minimal container; a typo or wrong -base/--diff path; running on Windows where git is present but path quoting breaks the --no-index invocation.

Related errors


AI-assisted analysis of dotnet/runtime@60108ba66e (2026-08-10). Data as JSON: /api/errors/ddd5b2842ea1fc19. Report an issue: GitHub.

Appendix: source

Thrown at src/coreclr/scripts/superpmi.py:2527

                                ran_jit_analyze = True

                        if not ran_jit_analyze:
                            logging.info("jit-analyze not found on PATH. Generate a diff analysis report by building jit-analyze from https://github.com/dotnet/jitutils and running:")
                            logging.info("    jit-analyze -r --base %s --diff %s", base_asm_location, diff_asm_location)

                        if self.coreclr_args.git_diff:
                            asm_diffs_location = os.path.join(asm_root_dir, "asm_diffs.diff")
                            git_diff_command = [ "git", "diff", "--output=" + asm_diffs_location, "--no-index", "--", base_asm_location, diff_asm_location ]
                            git_diff_time = time.time() * 1000
                            git_diff_proc = subprocess.Popen(git_diff_command, stdout=subprocess.PIPE)
                            git_diff_proc.communicate()
                            git_diff_elapsed_time = round((time.time() * 1000) - git_diff_time, 1)
                            git_diff_return_code = git_diff_proc.returncode
                            if git_diff_return_code == 0 or git_diff_return_code == 1: # 0 means no differences and 1 means differences
                                logging.info("Created git diff file at %s in %s ms", asm_diffs_location, git_diff_elapsed_time)
                                logging.info("-------")
                            else:
                                raise RuntimeError("Couldn't create git diff")

                    else:
                        logging.warning("No textual differences. Is this an issue with coredistools?")

                    # If we are not specifying custom metrics then print a summary here, otherwise leave the summarization up to jit-analyze.
                    if self.coreclr_args.metrics is None:
                        base_diff_sizes = [(int(r["Base ActualCodeBytes"]), int(r["Diff ActualCodeBytes"])) for r in diffs]
                        (num_size_improvements, num_size_regressions, num_size_same, byte_improvements, byte_regressions) = calculate_size_improvements_regressions(base_diff_sizes)

                        num_diffs_str = "{:,d} contexts with diffs".format(len(diffs))
                        logging.info("{} ({:,d} size improvements, {:,d} size regressions, {:,d} same size)".format(
                            num_diffs_str,
                            num_size_improvements,
                            num_size_regressions,
                            num_size_same,
                            byte_improvements,
                            byte_regressions))

View on GitHub (pinned to 60108ba66e)