{"record":{"id":"a08687ba0a03a84f","repo":"dotnet/runtime","slug":"unable-to-find-mingit-asset-for-arch-arch-ava","errorCode":null,"errorMessage":"Unable to find MinGit asset for arch '{arch}'. Available assets: {[a['name'] for a in assets if 'MinGit' in a['name']]}","messagePattern":"Unable to find MinGit asset for arch '(.+?)'\\. Available assets: (.+?)","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"src/coreclr/scripts/superpmi_aspnet2.py","lineNumber":99,"sourceCode":"        print(\"git found\")\n        return\n    if sys.platform == \"win32\":\n        print(\"git not found, downloading portable git...\")\n        m = {\"x64\": \"64-bit\", \"arm64\": \"arm64\", \"x86\": \"32-bit\"}\n        assets = requests.get(\n            \"https://api.github.com/repos/git-for-windows/git/releases/latest\", timeout=100\n        ).json()[\"assets\"]\n        rx = re.compile(r\"^MinGit-.*-(32-bit|64-bit|arm64)\\.zip$\", re.I)\n        arch = \"x64\"\n        mach = platform.machine().lower()\n        if \"arm64\" in mach:\n            arch = \"arm64\"\n        elif mach in (\"x86\", \"i386\", \"i686\"):\n            arch = \"x86\"\n        try:\n            asset = next(a for a in assets if rx.match(a[\"name\"]) and m[arch] in a[\"name\"]) \n        except StopIteration:\n            raise RuntimeError(\n                f\"Unable to find MinGit asset for arch '{arch}'. Available assets: \"\n                f\"{[a['name'] for a in assets if 'MinGit' in a['name']]}\"\n            )\n        dest_str = str(dest)\n        os.makedirs(dest_str, exist_ok=True)\n        zip_path = os.path.join(dest_str, asset[\"name\"]) \n        with requests.get(asset[\"browser_download_url\"], stream=True) as r, open(zip_path, \"wb\") as f:\n            for c in r.iter_content(8192):\n                f.write(c)\n        git_dir = os.path.join(dest_str, \"git\")\n        shutil.rmtree(git_dir, ignore_errors=True)\n        with zipfile.ZipFile(zip_path) as z:\n            z.extractall(git_dir)\n        os.remove(zip_path)\n        cmd_path = os.path.join(git_dir, \"cmd\")\n        os.environ[\"PATH\"] = cmd_path + os.pathsep + os.environ.get(\"PATH\", \"\")\n        return\n","sourceCodeStart":81,"sourceCodeEnd":117,"githubUrl":"https://github.com/dotnet/runtime/blob/290d5ab72cc1102813fbc0406fb186ceadabc340/src/coreclr/scripts/superpmi_aspnet2.py#L81-L117","documentation":"Raised by ensure_git in superpmi_aspnet2.py when no asset in the latest git-for-windows GitHub release matches the regex `^MinGit-.*-(32-bit|64-bit|arm64)\\.zip$` for the detected arch. This is a Windows-Helix workaround to give crank a git binary.","triggerScenarios":"`shutil.which('git')` is None on win32, the GitHub releases API returns assets, but none match MinGit for {x64:'64-bit', arm64:'arm64', x86:'32-bit'} mapping (e.g. release naming changed, or a new arch like arm64 was detected but no arm64 MinGit exists).","commonSituations":"Git-for-windows release ships no arm64 MinGit (historically true for some releases); release tag naming format changed; GitHub API returned partial/rate-limited asset list; platform.machine() returned an unexpected value.","solutions":["Pre-install git on the Helix image so shutil.which('git') succeeds and this path is skipped.","Pin to a git-for-windows release tag that ships the needed arch asset (e.g. an arm64-capable release).","Update the regex / m mapping in ensure_git to match the current asset naming.","Handle GitHub API rate-limiting (check response for 'message':'API rate limit')."],"exampleFix":"// before\n# arch=arm64, release has no arm64 MinGit -> raises [191]\n// after\n# pre-stage MinGit on the image, or loosen the matcher:\nasset = next((a for a in assets if 'MinGit' in a['name']), None)\nif asset is None: raise RuntimeError('no MinGit asset at all')","handlingStrategy":"fallback","validationCode":"import shutil\nif shutil.which('git') is None and sys.platform == 'win32':\n    assets = requests.get('https://api.github.com/repos/git-for-windows/git/releases/latest', timeout=100).json().get('assets', [])\n    names = [a['name'] for a in assets if 'MinGit' in a['name']]\n    if not any(('arm64' in n) for n in names) and arch == 'arm64':\n        raise SystemExit('no arm64 MinGit in latest release; pre-stage git or pin a release')","typeGuard":"def mingit_asset_exists(arch: str, assets: list) -> bool:\n    import re\n    rx = re.compile(r'^MinGit-.*-(32-bit|64-bit|arm64)\\.zip$', re.I)\n    m = {'x64':'64-bit','arm64':'arm64','x86':'32-bit'}\n    return any(rx.match(a['name']) and m.get(arch,'') in a['name'] for a in assets)","tryCatchPattern":"try:\n    ensure_git(tools_dir)\nexcept RuntimeError as e:\n    if 'MinGit asset' in str(e):\n        preinstall_git_on_image(); ensure_git(tools_dir)","preventionTips":["Pre-install git on Helix images so ensure_git short-circuits","Pin to a git-for-windows release that ships your arch","Monitor the regex against upstream naming changes"],"tags":["windows","helix","network","aspnet","superpmi"],"analyzedSha":"290d5ab72cc1102813fbc0406fb186ceadabc340","analyzedAt":"2026-08-06T19:57:01.276Z","schemaVersion":2},"datasetVersion":"2026-08-06T23:17:07.152Z"}