Skip to content

[repo-assist] Fix intermittent git dependency restore failures via cross-process locking - #4407

Merged
dsyme merged 1 commit into
masterfrom
repo-assist/fix-issue-4266-git-cache-race-19822b7082d56da2
Aug 30, 2026
Merged

dsyme merged 1 commit into
masterfrom
repo-assist/fix-issue-4266-git-cache-race-19822b7082d56da2

Conversation

@github-actions

Copy link
Copy Markdown
Contributor

🤖 This is an automated pull request from Repo Assist, an AI assistant.

Closes #4266

Root cause

getSHA1OfBranch and downloadRemoteFiles in RemoteDownload.fs call Paket.Git.Handling.fetchCache, which runs raw git remote set-url origin ... / git remote update --prune directly against the shared git repo cache folder (Constants.GitRepoCacheFolder) with no cross-process synchronization.

When a multi-project solution with git dependencies is restored — e.g. via dotnet restore invoking Paket per-project, or on a fresh CI checkout where the cache folder doesn't yet exist — multiple processes/tasks can call fetchCache on the same cache folder concurrently. The concurrent git remote set-url/fetch operations race and fail with:

Fetching the git cache at ... failed. Message: Could not run "git remote set-url origin ..."

Fix

Wrap the fetchCache calls (in both getSHA1OfBranch's version-requirement resolution path and downloadRemoteFiles's actual checkout path) with RunInLockedAccessMode, Paket's existing cross-process locking primitive (Common/Utils.fs), which uses a paket.processlock file to serialize access to a folder across processes. This mechanism is already used for similar shared-resource protection elsewhere (RestoreProcess.fs, PublicAPI.fs).

This serializes git cache mutation per cache folder across concurrent Paket processes, eliminating the race, while leaving normal (non-conflicting) restores unaffected.

Trade-offs

  • Restores involving many distinct git dependencies restored in parallel will now serialize the cache-fetch step per repo folder rather than running fully concurrently. This is a small, bounded slowdown in exchange for correctness; the checkout step itself (checkoutToPaketFolder) remains unlocked since each project's checkout folder is distinct.

Test Status

  • dotnet build src/Paket.Core/Paket.Core.fsproj -c Release succeeds for both net461 and netstandard2.0 targets, no new warnings introduced.
  • This is a concurrency/race-condition bug that is difficult to reproduce deterministically in a unit/integration test. The fix was verified by code inspection: RunInLockedAccessMode is a well-established, already-used primitive in this codebase for exactly this class of shared-folder-access problem (e.g. issue Could not acquire lock to ...\paket.locked #3535's antivirus/lock-file history confirms its intended purpose).
  • No existing integration test scenario specifically exercises concurrent git-dependency restores; adding one was judged infeasible within scope of this fix due to the non-deterministic nature of the race.

Generated by 🌈 Repo Assist, see workflow run. Learn more.
Comment /repo-assist to run again

Add this agentic workflow to your repo

To install this agentic workflow, run

gh aw add githubnext/agentics/workflows/repo-assist.md@ae8d551f07c7ed7619f8c58c7bb4c3ac89395d38

…cking

Wrap fetchCache calls on the shared git repo cache folder with
RunInLockedAccessMode, the existing cross-process locking primitive
(paket.processlock) already used elsewhere (e.g. RestoreProcess.fs,
PublicAPI.fs). This prevents concurrent 'git remote set-url origin'
races when multiple projects/processes restore in parallel against
the same shared cache folder.

Closes #4266

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

git dependencies intermittently fail to restore

1 participant