argoproj/argo-workflows · error

cannot get LockName for a Semaphore without a ConfigMapRef o

Error message

cannot get LockName for a Semaphore without a ConfigMapRef or Database

What it means

getSemaphoreLockName reached its default branch: the SemaphoreRef has neither ConfigMapKeyRef nor Database set, so no lock identity can be derived. The controller cannot track or acquire a semaphore that names no backend.

Source

Thrown at workflow/sync/lock_name.go:69

func getSemaphoreLockName(sem *v1alpha1.SemaphoreRef, wfNamespace string) (*lockName, error) {
	switch {
	case sem.ConfigMapKeyRef != nil && sem.Database != nil:
		return nil, fmt.Errorf("invalid semaphore with both ConfigMapKeyRef and Database")
	case sem.ConfigMapKeyRef != nil:
		namespace := sem.Namespace
		if namespace == "" {
			namespace = wfNamespace
		}
		return newLockName(namespace, sem.ConfigMapKeyRef.Name, sem.ConfigMapKeyRef.Key, lockKindConfigMap), nil
	case sem.Database != nil:
		namespace := sem.Namespace
		if namespace == "" {
			namespace = wfNamespace
		}
		return newLockName(namespace, sem.Database.Key, "", lockKindDatabase), nil
	default:
		return nil, fmt.Errorf("cannot get LockName for a Semaphore without a ConfigMapRef or Database")
	}
}

func getMutexLockName(mtx *v1alpha1.Mutex, wfNamespace string) *lockName {
	namespace := mtx.Namespace
	if namespace == "" {
		namespace = wfNamespace
	}
	if mtx.Database {
		return newLockName(namespace, mtx.Name, "", lockKindDatabase)
	}
	return newLockName(namespace, mtx.Name, "", lockKindMutex)
}

func (i *syncItem) lockName(wfNamespace string) (*lockName, error) {
	switch {
	case i.semaphore != nil:
		return getSemaphoreLockName(i.semaphore, wfNamespace)

View on GitHub (pinned to 35bff19146)

Solutions

  1. Set either `configMapKeyRef` (name+key) or `database` (key) on the semaphore
  2. Lint with `argo lint` before submitting to catch the empty ref
  3. Inspect the submitted workflow spec (`argo get <wf> -o yaml`) to see what actually rendered

Example fix

// before
synchronization:
  semaphore: {}
// after
synchronization:
  semaphore:
    configMapKeyRef:
      name: my-cm
      key: my-key
Defensive patterns

Strategy: validation

Validate before calling

func validateSemaphoreRef(sem *SemaphoreRef) error {
    if sem == nil || (sem.ConfigMapKeyRef == nil && sem.Database == nil) {
        return fmt.Errorf("semaphore requires configMapKeyRef or database")
    }
    return nil
}

Type guard

func semaphoreRefHasBackend(sem *SemaphoreRef) bool {
    return sem != nil && (sem.ConfigMapKeyRef != nil || sem.Database != nil)
}

Try / catch

err := wf.Submit(ctx)
if err != nil && strings.Contains(err.Error(), "without a ConfigMapRef or Database") {
    return fmt.Errorf("populate the semaphore ref in the spec: %w", err)
}

Prevention

When it happens

Trigger: A workflow declares `synchronization.semaphore: {}` (empty object) or a rendered template resolves the semaphore ref to nil fields; getSemaphoreLockName falls through to default.

Common situations: Partial template substitution leaving the semaphore block empty; YAML mistakes like a mis-indented configMapKeyRef so it parses as a sibling key; programmatically constructed workflow specs with unset fields.

Related errors


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