argoproj/argo-workflows · error
cannot acquire lock from nil Synchronization
Error message
cannot acquire lock from nil Synchronization
What it means
Manager.TryAcquire requires a non-nil *wfv1.Synchronization describing what to acquire. A nil reference means the caller passed no synchronization/mutex spec at all, so the call is rejected immediately. This is a programming/configuration bug in the caller, not a transient condition.
Source
Thrown at workflow/sync/sync_manager.go:455
}
if reason != "" {
stale(reason)
}
}
}
}
sm.log.Info(ctx, "Sync manager initialized successfully")
return staleHolds, nil
}
// TryAcquire tries to acquire the lock from semaphore.
// It returns status of acquiring a lock , status of Workflow status updated, waiting message if lock is not available, the failed lock, and any error encountered
func (sm *Manager) TryAcquire(ctx context.Context, wf *wfv1.Workflow, nodeName string, syncLockRef *wfv1.Synchronization) (bool, bool, string, string, error) {
sm.lock.Lock()
defer sm.lock.Unlock()
if syncLockRef == nil {
return false, false, "", "", fmt.Errorf("cannot acquire lock from nil Synchronization")
}
failedLockName := ""
syncItems, err := allSyncItems(syncLockRef)
if err != nil {
return false, false, "", failedLockName, fmt.Errorf("requested configuration is invalid: %w", err)
}
holderKey := getHolderKey(wf, nodeName)
lockKeys := make([]string, len(syncItems))
for i, syncItem := range syncItems {
syncLockName, lockNameErr := syncItem.lockName(wf.Namespace)
if lockNameErr != nil {
return false, false, "", failedLockName, fmt.Errorf("requested configuration is invalid: %w", lockNameErr)
}
sm.log.WithField("syncLockName", syncLockName).Info(ctx, "TryAcquire")
lockKeys[i] = syncLockName.String(ctx)
}View on GitHub (pinned to 35bff19146)
Solutions
- Check the template declares synchronization.semaphore or synchronization.mutex before calling TryAcquire
- Skip the TryAcquire call when the node has no synchronization reference
- Verify the workflow spec was fully unmarshaled with no dropped fields
Example fix
// before
ok, _, msg, lock, err := sm.TryAcquire(ctx, wf, nodeName, nil)
// after
if tmpl.Synchronization != nil {
ok, _, msg, lock, err := sm.TryAcquire(ctx, wf, nodeName, tmpl.Synchronization)
} Defensive patterns
Strategy: validation
Validate before calling
if syncRef == nil {
// node has no synchronization; do not call TryAcquire
return
} Type guard
func hasSync(tmpl *wfv1.Template) bool {
return tmpl != nil && tmpl.Synchronization != nil
} Try / catch
if _, _, _, _, err := sm.TryAcquire(ctx, wf, node, ref); err != nil && strings.Contains(err.Error(), "nil Synchronization") { /* skip: no sync declared */ } Prevention
- Never call TryAcquire without a resolved Synchronization object
- Validate workflow specs with workflow/validate before processing
- Unit-test operators against templates without synchronization
When it happens
Trigger: Calling TryAcquire with syncLockRef == nil, e.g. when the node's template declares neither semaphore nor mutex but the operator loop still invokes TryAcquire.
Common situations: Custom controller code calling TryAcquire without checking whether the template declares a synchronization; partial YAML unmarshal dropping the synchronization field.
Related errors
- cannot re-establish %s %q held by workflow %s/%s at startup:
- requested configuration is invalid: %w
- couldn't decode locks for session: %w
- synchronization database session is not available
- failed to get current lock holders: %w
AI-assisted analysis of argoproj/argo-workflows@35bff19146 (2026-09-03).
Data as JSON: /api/errors/ef2adef61a49e326.
Report an issue: GitHub.