Skip to content

fix: add mutex to LocalRepositoryCache to prevent concurrent map panic - #6055

Open
jun-mercury wants to merge 1 commit into
nektos:masterfrom
jun-mercury:fix/local-repository-cache-race
Open

fix: add mutex to LocalRepositoryCache to prevent concurrent map panic#6055
jun-mercury wants to merge 1 commit into
nektos:masterfrom
jun-mercury:fix/local-repository-cache-race

Conversation

@jun-mercury

Copy link
Copy Markdown

Summary

LocalRepositoryCache.CacheDirCache is a plain map[string]string accessed concurrently by Fetch (write) and GetTarArchive (read) when multiple matrix jobs resolve --local-repository actions in parallel. This causes an intermittent panic:

fatal error: concurrent map read and map write

goroutine 313114 [running]:
LocalRepositoryCache.GetTarArchive(...)
    local_repository_cache.go:47

This is the same class of bug as #6028 (fixed in #6029 for GoGitActionCache), but in the --local-repository code path. The GoGitActionCache fix added per-repo mutexes to serialize git operations — this PR applies the same pattern to LocalRepositoryCache.

Fix

Add a sync.RWMutex to serialize access to CacheDirCache:

  • Fetch(): write lock when updating the cache
  • GetTarArchive(): read lock when looking up cached paths

LocalRepositories is set at initialization and only read after, so it does not need synchronization.

Reproduction

  1. Create a workflow calling a reusable workflow with a matrix (2+ entries)
  2. Each matrix job references the same external action via --local-repository
  3. Run with act using containerized runners
  4. Failure is intermittent — depends on goroutine scheduling

Crash observed in CI: https://github.com/MercuryTechnologies/mercury-web-backend/actions/runs/23767992978/job/69252242640

Context

Hi @cplee — this is a companion to #6029, which we submitted a few weeks ago for the same race condition in GoGitActionCache. We've been running act with the #6029 patch in our CI for a couple of weeks now (hundreds of runs across multiple environments) and it's been stable. This new crash surfaced because LocalRepositoryCache has the same unprotected map pattern but in a different code path that we didn't catch initially.

We'd appreciate a review when you get a chance — both this and #6029 are small, targeted fixes. Happy to address any feedback.

Related: #6028 (issue), #6029 (GoGitActionCache fix)

LocalRepositoryCache.CacheDirCache is a plain map[string]string
accessed concurrently by Fetch (write) and GetTarArchive (read)
when multiple matrix jobs resolve --local-repository actions in
parallel. This causes:

  fatal error: concurrent map read and map write
  goroutine ... [running]:
  LocalRepositoryCache.GetTarArchive(...)
      local_repository_cache.go:47

Add a sync.RWMutex to serialize access to CacheDirCache:
- Fetch: write lock when updating the cache
- GetTarArchive: read lock when looking up cached paths

LocalRepositories is set at initialization and only read after,
so it does not need synchronization.

This is the same class of bug as nektos#6028 (fixed in nektos#6029 for
GoGitActionCache), but in the --local-repository code path.
@codecov

codecov Bot commented Apr 5, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 76.90%. Comparing base (bd4bc99) to head (6ea89d9).
⚠️ Report is 46 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #6055      +/-   ##
==========================================
+ Coverage   74.65%   76.90%   +2.24%     
==========================================
  Files          73       74       +1     
  Lines       11139     9325    -1814     
==========================================
- Hits         8316     7171    -1145     
+ Misses       2186     1510     -676     
- Partials      637      644       +7     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@HAHGX

HAHGX commented Apr 8, 2026

Copy link
Copy Markdown

@jun-mercury FYI

kjelly added a commit to kjelly/act that referenced this pull request Jun 2, 2026
…nd fixes

Features:
- Add git worktree support for container mounts (nektos#6075)
- Add --unique-container-names flag for parallel act instances (nektos#6062)
- Add workflow_call inputs test coverage

Fixes:
- Resolve Dockerfile context from action.yml location (nektos#6085, nektos#6087)
- Remove unsafe exec() in action.go (nektos#6082)
- Tolerate unknown protobuf fields in artifacts v7 (nektos#6053)
- Add mutex to LocalRepositoryCache (nektos#6055)
- Prevent path escape in CopyTarStream (nektos#6093)
- Send gh token only for correct hostname (nektos#6078)
- Add deployment boolean and queue field to workflow schema (nektos#6097, nektos#6098)
- Add artifact-metadata permission to schema (nektos#6069)
- Clearer job status with emoji indicators (nektos#6080)
- Use readlink for action canonical path (nektos#6068)

Excluded: Dependabot dependency updates
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants