Bug report
Describe the bug
When multiple matrix jobs within a reusable workflow concurrently fetch the same action via GoGitActionCache, a race condition causes intermittent failures:
failed to read 'action.yml' from action 'Assume deploy ASG Role' with path '' of step: file does not exist
or:
GoGitActionCache failed to fetch https://github.com/... : repository not found: Repository not found.
Root cause
GoGitActionCache.Fetch() operates on a shared bare git repo at gitPath (derived from cacheDir). When two goroutines call Fetch() for the same repo concurrently:
- Both call
git.PlainInit(gitPath, true) — one succeeds, one gets ErrRepositoryAlreadyExists
- Both create anonymous remotes and call
FetchContext() concurrently on the same bare repo
- The deferred
DeleteBranch(branchName) cleanup in one goroutine can remove objects that another goroutine's GetTarArchive() is reading
This manifests as:
action.yml not found (objects not yet written when read)
- Repository not found (bare repo in inconsistent state during concurrent init/fetch)
To reproduce
- Create a workflow with a reusable workflow that uses
fromJSON() matrix with 2+ entries
- Each matrix job must reference the same external action (e.g.,
aws-actions/configure-aws-credentials)
- Run with act using containerized runners (GoGitActionCache is used)
- The failure is intermittent — depends on goroutine scheduling
Expected behavior
Concurrent matrix jobs should be able to safely share the action cache.
Suggested fix
Add a per-repo sync.Mutex (stored in a sync.Map on GoGitActionCache) to serialize Fetch() and GetTarArchive() calls for the same gitPath. Different repos remain fully parallel.
act version
v0.2.84
Bug report
Describe the bug
When multiple matrix jobs within a reusable workflow concurrently fetch the same action via
GoGitActionCache, a race condition causes intermittent failures:or:
Root cause
GoGitActionCache.Fetch()operates on a shared bare git repo atgitPath(derived fromcacheDir). When two goroutines callFetch()for the same repo concurrently:git.PlainInit(gitPath, true)— one succeeds, one getsErrRepositoryAlreadyExistsFetchContext()concurrently on the same bare repoDeleteBranch(branchName)cleanup in one goroutine can remove objects that another goroutine'sGetTarArchive()is readingThis manifests as:
action.ymlnot found (objects not yet written when read)To reproduce
fromJSON()matrix with 2+ entriesaws-actions/configure-aws-credentials)Expected behavior
Concurrent matrix jobs should be able to safely share the action cache.
Suggested fix
Add a per-repo
sync.Mutex(stored in async.MaponGoGitActionCache) to serializeFetch()andGetTarArchive()calls for the samegitPath. Different repos remain fully parallel.act version
v0.2.84