{"record":{"id":"79d5fa45d918857f","repo":"argoproj/argo-workflows","slug":"failed-to-initialize-semaphore-s-w-79d5fa","errorCode":null,"errorMessage":"failed to initialize semaphore %s: %w","messagePattern":"failed to initialize semaphore (.+?): %w","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"workflow/sync/semaphore.go","lineNumber":47,"sourceCode":"\t\tname:     name,\n\t\tlockType: lockTypeSemaphore,\n\t}\n\tsem := &prioritySemaphore{\n\t\tname:         name,\n\t\tlimitGetter:  newCachedLimit(configMapGetter, syncLimitCacheTTL),\n\t\tpending:      &priorityQueue{itemByKey: make(map[string]*item)},\n\t\tsemaphore:    sema.NewWeighted(int64(0)),\n\t\tlockHolder:   make(map[string]bool),\n\t\tnextWorkflow: nextWorkflow,\n\t\tlogger:       logger.get,\n\t}\n\t// Resolve the limit directly through limitGetter rather than getLimit(), since\n\t// getLimit() falls back to the cache's zero-value on a fetch error, which would\n\t// make a genuine error indistinguishable from a semaphore that legitimately\n\t// starts at limit 0 (e.g. an \"approval gate\" held closed until raised).\n\tlimit, changed, err := sem.limitGetter.get(ctx, name)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to initialize semaphore %s: %w\", name, err)\n\t}\n\tif changed && !sem.resize(ctx, limit) {\n\t\treturn nil, fmt.Errorf(\"failed to size semaphore %s to limit %d\", name, limit)\n\t}\n\treturn sem, nil\n}\n\nfunc (s *prioritySemaphore) getLimit(ctx context.Context) int {\n\tlimit, changed, err := s.limitGetter.get(ctx, s.name)\n\tif err != nil {\n\t\t// Fall back to the last known limit (returned by the cache alongside\n\t\t// the error). Returning 0 here would make release() treat a transient\n\t\t// fetch failure as a downward resize and permanently leak a slot.\n\t\ts.logger(ctx).WithError(err).WithFields(logging.Fields{\n\t\t\t\"name\":          s.name,\n\t\t\t\"fallbackLimit\": limit,\n\t\t}).Error(ctx, \"failed to get limit for semaphore, using last known limit\")\n\t\treturn limit","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/argoproj/argo-workflows/blob/35bff19146f5a6ada77468c431f2624bd577e373/workflow/sync/semaphore.go#L29-L65","documentation":"newInternalSemaphore resolves the semaphore's limit via limitGetter.get before first use. If that fetch errors, the error is wrapped as 'failed to initialize semaphore' rather than silently defaulting the limit to 0 — a genuine failure stays distinguishable from an approval-gate semaphore that legitimately starts at limit 0.","triggerScenarios":"initializeSemaphore is called during controller startup or when a semaphore is first needed; limitGetter.get (ConfigMap read or DB query) returns an error — missing ConfigMap, RBAC denial, DB failure.","commonSituations":"Semaphore ConfigMap deleted or in a different namespace; controller service account lacking get rights on the ConfigMap; database-backed semaphore with unreachable DB; typo in the semaphore name/key.","solutions":["Verify the semaphore ConfigMap exists in the workflow's namespace with the configured key, or the DB row exists","Fix controller RBAC so it can read the ConfigMap (`argoproj.io` sync ConfigMaps)","Check controller logs for the wrapped underlying error to identify the exact source","Restart/reconcile the workflow after fixing so initialization is retried"],"exampleFix":"// before: missing ConfigMap\nkubectl get configmap my-semaphore-cm -n argo   # NotFound\n// after: create it\nkubectl create configmap my-semaphore-cm -n argo --from-literal=limit=3","handlingStrategy":"try-catch","validationCode":"// ensure the semaphore ConfigMap exists and is readable before submitting\nkubectl get configmap <name> -n <wf-namespace> \\\n  && kubectl auth can-i get configmap/<name> -n <wf-namespace> --as=system:serviceaccount:argo:argo-server","typeGuard":null,"tryCatchPattern":"sem, err := manager.InitializeSemaphore(ctx, name)\nif err != nil && strings.Contains(err.Error(), \"failed to initialize semaphore\") {\n    return fmt.Errorf(\"check ConfigMap/DB for semaphore %q: %w\", name, err)\n}","preventionTips":["Create semaphore ConfigMaps before submitting dependent workflows","Grant the controller SA read access to sync ConfigMaps","Keep semaphore names/keys consistent across namespaces and environments"],"tags":["semaphore","initialization","configmap"],"backgroundTag":"semaphore-init-failure","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"}