argoproj/argo-workflows · critical
synchronization database session is not available
Error message
synchronization database session is not available
What it means
One of the lock keys requires a database-backed semaphore, but the Manager was built without a DB session proxy (dbInfo.SessionProxy == nil). Without the session the manager cannot read or update DB lock state, so acquisition is refused rather than silently bypassing the DB lock.
Source
Thrown at workflow/sync/sync_manager.go:484
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)
}
if ok, msg, prepLockName, prepErr := sm.prepAcquire(ctx, wf, holderKey, syncItems, lockKeys); !ok {
return false, false, msg, prepLockName, prepErr
}
needDB, err := needDBSession(ctx, lockKeys)
if err != nil {
return false, false, "", failedLockName, fmt.Errorf("couldn't decode locks for session: %w", err)
}
if needDB && sm.dbInfo.SessionProxy == nil {
return false, false, "", failedLockName, fmt.Errorf("synchronization database session is not available")
}
if needDB {
var updated bool
var already bool
var msg string
var newly []*acquiredLock
backoff := dbRetryBackoff
// tryAcquireImpl mutates wf.Status.Synchronization in memory before the
// transaction commits. Snapshot it and roll each failed attempt back, so
// that attempts are independent and an error return leaves the caller's
// status exactly as it was - otherwise an abort leaves a Holding entry
// for a row the database rolled back, which would be persisted and then
// failed as a stale hold on the next controller restart.
syncStatus := wf.Status.Synchronization.DeepCopy()
attempt := 0
err = retry.OnError(backoff, IsRetryableSyncError, func() error {
attempt++
sm.log.WithFields(logging.Fields{View on GitHub (pinned to 35bff19146)
Solutions
- Enable and configure synchronization DB persistence in the controller config
- Point the controller at the correct Postgres/MySQL instance used for sync state
- Restart the controller so the session proxy is initialized
- Switch the workflow to ConfigMap-based synchronization if no DB is intended
Example fix
// before (controller config)
# no sync database configured
// after
syncDatabase:
postgresql:
host: postgres
port: 5432
database: argo_sync Defensive patterns
Strategy: validation
Validate before calling
if needsDB(lockKeys) && manager.SessionProxy == nil {
return errors.New("configure sync DB persistence before using DB-backed semaphores")
} Type guard
func dbSessionReady(sm *sync.Manager) bool { return sm != nil && sm.DBInfo != nil && sm.DBInfo.SessionProxy != nil } Try / catch
if _, _, _, _, err := sm.TryAcquire(...); err != nil && strings.Contains(err.Error(), "database session is not available") { /* alert: persistence misconfigured */ } Prevention
- Verify persistence settings in controller startup health checks
- Document DB requirements for DB-backed semaphores
- Alert on 'synchronization database session is not available' occurrences
When it happens
Trigger: A workflow uses a database-sourced semaphore (sync config in Postgres/MySQL) while the controller runs without synchronization DB persistence configured or the session is unavailable at runtime.
Common situations: Controller installed with persistence disabled while workflows reference DB-backed sync; wrong DB credentials so SessionProxy was never created; DB lost after startup.
Related errors
- database session is not available for semaphore %s
- failed to initialize semaphore %s: %w
- requested configuration is invalid: %w
- failed to get current lock holders: %w
- database session is not available for mutex %s
AI-assisted analysis of argoproj/argo-workflows@35bff19146 (2026-09-03).
Data as JSON: /api/errors/9f94c6cd00c107cf.
Report an issue: GitHub.