{"record":{"id":"a9c96362b139aa59","repo":"argoproj/argo-workflows","slug":"invalid-semaphore-with-both-configmapkeyref-and-da","errorCode":null,"errorMessage":"invalid semaphore with both ConfigMapKeyRef and Database","messagePattern":"invalid semaphore with both ConfigMapKeyRef and Database","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"workflow/sync/lock_name.go","lineNumber":55,"sourceCode":"\nfunc (ln *lockName) GetNamespace() string    { return ln.namespace }\nfunc (ln *lockName) GetResourceName() string { return ln.resourceName }\nfunc (ln *lockName) GetKey() string          { return ln.key }\nfunc (ln *lockName) getKind() lockKind       { return ln.kind }\n\nfunc newLockName(namespace, resourceName, lockKey string, kind lockKind) *lockName {\n\treturn &lockName{\n\t\tnamespace:    namespace,\n\t\tresourceName: resourceName,\n\t\tkey:          lockKey,\n\t\tkind:         kind,\n\t}\n}\n\nfunc getSemaphoreLockName(sem *v1alpha1.SemaphoreRef, wfNamespace string) (*lockName, error) {\n\tswitch {\n\tcase sem.ConfigMapKeyRef != nil && sem.Database != nil:\n\t\treturn nil, fmt.Errorf(\"invalid semaphore with both ConfigMapKeyRef and Database\")\n\tcase sem.ConfigMapKeyRef != nil:\n\t\tnamespace := sem.Namespace\n\t\tif namespace == \"\" {\n\t\t\tnamespace = wfNamespace\n\t\t}\n\t\treturn newLockName(namespace, sem.ConfigMapKeyRef.Name, sem.ConfigMapKeyRef.Key, lockKindConfigMap), nil\n\tcase sem.Database != nil:\n\t\tnamespace := sem.Namespace\n\t\tif namespace == \"\" {\n\t\t\tnamespace = wfNamespace\n\t\t}\n\t\treturn newLockName(namespace, sem.Database.Key, \"\", lockKindDatabase), nil\n\tdefault:\n\t\treturn nil, fmt.Errorf(\"cannot get LockName for a Semaphore without a ConfigMapRef or Database\")\n\t}\n}\n\nfunc getMutexLockName(mtx *v1alpha1.Mutex, wfNamespace string) *lockName {","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/argoproj/argo-workflows/blob/35bff19146f5a6ada77468c431f2624bd577e373/workflow/sync/lock_name.go#L37-L73","documentation":"getSemaphoreLockName validates a SemaphoreRef and rejects one that sets both ConfigMapKeyRef and Database — a semaphore must resolve to exactly one backend. This is a configuration validation error raised while computing the lock name for a workflow's synchronization entry.","triggerScenarios":"A workflow/template specifies synchronization.semaphore with both `configMapKeyRef` and `database` fields populated; validation/lock-name resolution in the controller or lint hits the first switch case.","commonSituations":"Copy-paste editing a workflow that migrates from ConfigMap-based to database-based synchronization without removing the old field; templating/Helm values merging two sources of a semaphore spec.","solutions":["Remove the `configMapKeyRef` field if you intend database-backed synchronization","Remove the `database` field if you intend ConfigMap-backed synchronization","Lint the workflow before submit (`argo lint`) to catch the ambiguous spec early"],"exampleFix":"// before\nsynchronization:\n  semaphore:\n    configMapKeyRef:\n      name: my-cm\n      key: my-key\n    database:\n      key: my-lock\n// after\nsynchronization:\n  semaphore:\n    database:\n      key: my-lock","handlingStrategy":"validation","validationCode":"func validateSemaphore(sem map[string]any) error {\n    _, hasCM := sem[\"configMapKeyRef\"]\n    _, hasDB := sem[\"database\"]\n    if hasCM && hasDB {\n        return fmt.Errorf(\"semaphore must set only one of configMapKeyRef or database\")\n    }\n    if !hasCM && !hasDB {\n        return fmt.Errorf(\"semaphore must set configMapKeyRef or database\")\n    }\n    return nil\n}","typeGuard":"func hasExactlyOneBackend(sem *SemaphoreRef) bool {\n    if sem == nil { return false }\n    return (sem.ConfigMapKeyRef != nil) != (sem.Database != nil)\n}","tryCatchPattern":"err := wf.Submit(ctx)\nif err != nil && strings.Contains(err.Error(), \"both ConfigMapKeyRef and Database\") {\n    return fmt.Errorf(\"fix workflow spec: %w\", err)\n}","preventionTips":["Run `argo lint` on all workflows before submit","When migrating between ConfigMap and DB semaphores, delete the old field in the same change","Use schema-validated templates/CRDs rather than free-form YAML"],"tags":["configuration","semaphore","validation"],"backgroundTag":"ambiguous-semaphore-config","analyzedSha":"35bff19146f5a6ada77468c431f2624bd577e373","analyzedAt":"2026-09-03T19:34:35.908Z","contentChangedAt":"2026-09-03T19:34:35.908Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}