argoproj/argo-workflows · critical

database session is not available for semaphore %s

Error message

database session is not available for semaphore %s

What it means

initializeSemaphore builds a semaphore for a decoded lock; for lockKindDatabase it requires the manager's DB session proxy and returns 'database session is not available for semaphore <name>' when it is nil. Called during prepAcquire, this blocks acquisition of any DB-backed semaphore when persistence is not configured.

Source

Thrown at workflow/sync/sync_manager.go:856

func (sm *Manager) getCurrentLockHolders(ctx context.Context, lock string) ([]string, error) {
	if concurrency, ok := sm.syncLockMap[lock]; ok {
		return concurrency.getCurrentHolders(ctx)
	}
	return nil, nil
}

func (sm *Manager) initializeSemaphore(ctx context.Context, semaphoreName string) (semaphore, error) {
	lock, err := DecodeLockName(ctx, semaphoreName)
	if err != nil {
		return nil, err
	}
	switch lock.getKind() {
	case lockKindConfigMap:
		return newInternalSemaphore(ctx, semaphoreName, sm.nextWorkflow, sm.getSyncLimit, sm.syncLimitCacheTTL)
	case lockKindDatabase:
		if sm.dbInfo.SessionProxy == nil {
			return nil, fmt.Errorf("database session is not available for semaphore %s", semaphoreName)
		}
		return newDatabaseSemaphore(ctx, semaphoreName, lock.getDBKey(), sm.nextWorkflow, sm.dbInfo, sm.syncLimitCacheTTL)
	default:
		return nil, fmt.Errorf("invalid lock kind %s when initializing semaphore", lock.getKind())
	}
}

func (sm *Manager) initializeMutex(ctx context.Context, mutexName string) (semaphore, error) {
	lock, err := DecodeLockName(ctx, mutexName)
	if err != nil {
		return nil, err
	}
	switch lock.getKind() {
	case lockKindMutex:
		return newInternalMutex(mutexName, sm.nextWorkflow), nil
	case lockKindDatabase:
		if sm.dbInfo.SessionProxy == nil {
			return nil, fmt.Errorf("database session is not available for mutex %s", mutexName)

View on GitHub (pinned to 35bff19146)

Solutions

  1. Enable synchronization DB persistence in the controller configuration
  2. Verify DB credentials/connectivity so SessionProxy initializes at startup
  3. Restart the controller after fixing persistence config
  4. Convert the semaphore to ConfigMap-based if DB sync is unnecessary
Defensive patterns

Strategy: validation

Validate before calling

lock, _ := sync.DecodeLockName(ctx, key)
if lock.GetKind() == sync.LockKindDatabase && !dbSessionReady(manager) {
    return errors.New("DB-backed semaphore requires configured sync persistence")
}

Type guard

func canUseDBLock(sm *sync.Manager) bool { return sm != nil && sm.DBInfo != nil && sm.DBInfo.SessionProxy != nil }

Try / catch

if err != nil && strings.Contains(err.Error(), "database session is not available for semaphore") { /* configure persistence, requeue */ }

Prevention

When it happens

Trigger: prepAcquire resolves a lock decoded as lockKindDatabase while sm.dbInfo.SessionProxy is nil — DB-backed sync config exists but the controller has no sync DB session (persistence disabled or DB down at init).

Common situations: Deploying workflows with SQL-backed synchronization on a controller without DB persistence; wrong DB credentials so the session proxy never initialized; DB lost after controller start.

Related errors


AI-assisted analysis of argoproj/argo-workflows@35bff19146 (2026-09-03). Data as JSON: /api/errors/eec38ad28253b77e. Report an issue: GitHub.