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
- Run the git diff command printed in the debug log manually to see git's real stderr message.
- Verify both base_asm_location and diff_asm_location exist and contain .dasm files before enabling --git_diff.
- Ensure git is installed and on PATH (git --version succeeds) in the execution environment.
- 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
- Ensure both asm output directories exist and contain .dasm files before enabling --git_diff.
- Confirm git is installed and on PATH in CI containers.
- Capture stderr from the git subprocess so failures are diagnosable.
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
- Couldn't determine baseline git hash
- Couldn't determine current git hash
- Couldn't determine list of JIT changes starting with…
- Couldn't determine newest 'main' git hash
- No JIT changes found starting with baseline hash
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)