multica-ai/multica · warning · ErrRepoBusy
ErrRepoBusy
ErrRepoBusy
Error message
repository is busy
What it means
Sentinel error ErrRepoBusy in server/internal/daemon/repocache/cache.go: a foreground checkout requested a repository whose dedicated repoLock was held (by another clone/fetch/worktree-add/ref-update, or by low-priority maintenance), and the caller's bounded wait expired before the lock became free. git's own lockfiles cannot tolerate parallel mutations on one repo, so the cache serializes them; callers that advertised retry support are expected to convert this into a retryable response instead of blocking to the transport deadline.
Source
Thrown at server/internal/daemon/repocache/cache.go:176
}
// Cache manages bare git clones for workspace repositories.
type Cache struct {
root string // base directory for all caches (e.g. ~/multica_workspaces/.repos)
logger *slog.Logger
// repoLocks maps bare repo path → dedicated mutex. Any mutating operation
// on a given bare repo (clone, fetch, worktree add, ref update) must
// hold its lock — git's own lockfiles (packed-refs.lock, config.lock,
// worktree admin dirs) don't tolerate parallel mutations on the same
// repo. Separate repos are independent and run concurrently.
repoLocks sync.Map // barePath -> *repoLock
}
// ErrRepoBusy means a foreground checkout could not acquire its repository
// within the caller's bounded wait. Callers that advertised retry support can
// turn this into a retryable HTTP response instead of waiting until their
// transport deadline expires.
var ErrRepoBusy = errors.New("repository is busy")
// Activity is the path-free repository coordination state exposed through the
// daemon health endpoint. It is diagnostic only.
type Activity struct {
MaintenanceActive int
ForegroundWaiters int
}
// repoLock is a foreground-priority mutex. Ordinary cache mutations serialize
// exactly as they did with sync.Mutex. Low-priority maintenance is different:
// it only starts on an idle repository and receives a context that is cancelled
// as soon as a foreground operation queues. The maintenance holder remains
// responsible for stopping its Git process tree before unlocking.
type repoLock struct {
mu sync.Mutex
held bool
maintenance bool
maintenanceCancel context.CancelCauseFuncView on GitHub (pinned to 2c0912b6ec)
Solutions
- Retry the operation after a backoff — the lock holder will usually finish and the retry acquires the lock.
- Stagger task starts that target the same repo to avoid lock contention.
- If it recurs constantly, inspect the daemon health Activity (ForegroundWaiters/MaintenanceActive) to see whether maintenance is starving foreground ops.
- Callers: map ErrRepoBusy to a retryable HTTP response (e.g. 429/503 with Retry-After) as the doc comment instructs, not to a hard failure.
Example fix
// go — caller-side retryable mapping
if errors.Is(err, repocache.ErrRepoBusy) {
w.Header().Set("Retry-After", "2")
http.Error(w, "repository is busy, retry shortly", http.StatusTooManyRequests)
return
} Defensive patterns
Strategy: retry
Try / catch
if errors.Is(err, repocache.ErrRepoBusy) {
w.Header().Set("Retry-After", "2")
http.Error(w, "repository is busy, retry shortly", http.StatusTooManyRequests)
return
}
// client side: honor Retry-After and re-issue the request Prevention
- Map ErrRepoBusy to a retryable HTTP status with Retry-After — never let it consume the transport deadline.
- Stagger task starts that target the same repository.
- Watch the daemon health Activity counters to detect maintenance starving foreground waiters.
When it happens
Trigger: Two tasks targeting the same repo starting near-simultaneously; a background maintenance pass (GC/fetch) holding the lock when a foreground checkout queues; a large clone starving subsequent waiters past their bounded wait.
Common situations: Parallel agent runs on the same repository; scheduled repo maintenance overlapping task start; big monorepo clones taking longer than the foreground wait budget.
Related errors
- daemon has %d active %s; setup saved the new configuration b
- daemon exited during startup.
- cloud pat verifier unavailable
- repo is not configured for this workspace
- local_directory: local_path is empty
AI-assisted analysis of multica-ai/multica@2c0912b6ec (2026-08-15).
Data as JSON: /api/errors/c8387533b3ecbff6.
Report an issue: GitHub.