argoproj/argo-workflows · error
expected no more than 1 workflow, got %d
Error message
expected no more than 1 workflow, got %d
What it means
deleteOffloadedNodesForWorkflow (workflow/controller/controller.go:869) expects the UID index to hold at most one workflow per UID. If the indexer returns more than one object for the same UID, this error is thrown with the actual count. It signals corrupt/duplicated informer-cache state (the UID is supposed to be unique per object).
Source
Thrown at workflow/controller/controller.go:869
un, ok = obj.(*unstructured.Unstructured)
if !ok {
return fmt.Errorf("object %+v is not an unstructured", obj)
}
wf, err = util.FromUnstructured(un)
if err != nil {
return err
}
// workflow might still be hydrated
if wfc.hydrator.IsHydrated(wf) {
logger.WithField("uid", wf.UID).Info(ctx, "Hydrated workflow encountered")
err = wfc.hydrator.Dehydrate(ctx, wf)
if err != nil {
return err
}
}
default:
return fmt.Errorf("expected no more than 1 workflow, got %d", l)
}
for _, version := range versions {
// skip delete if offload is live
if wf != nil && wf.Status.OffloadNodeStatusVersion == version {
continue
}
if err := wfc.offloadNodeStatusRepo.Delete(ctx, uid, version); err != nil {
return err
}
}
return nil
}
func (wfc *WorkflowController) archivedWorkflowGarbageCollector(ctx context.Context) {
defer runtimeutil.HandleCrashWithContext(ctx, runtimeutil.PanicHandlers...)
logger := logging.RequireLoggerFromContext(ctx)
logger = logger.WithField("component", "archived_wf_garbage_collector")View on GitHub (pinned to 35bff19146)
Solutions
- Restart the workflow controller to rebuild the informer cache; the error is logged and GC retries.
- Inspect the UIDIndex index function — it must map exactly one indexer entry per UID.
- In tests, ensure no two objects with the same UID are added to the indexer.
Defensive patterns
Strategy: validation
Validate before calling
// Sanity-check the UID index maps one entry per UID
dups := indexer.ByIndex(indexes.UIDIndex, uid)
if len(dups) > 1 {
log.Fatalf("UID %s has %d indexer entries; index function is broken", uid, len(dups))
} Try / catch
switch l := len(workflows); l {
case 0: /* deleted */
case 1: /* process */
default:
return fmt.Errorf("expected no more than 1 workflow, got %d", l)
} Prevention
- Restart the controller if duplicate indexer entries appear (rebuilds cache)
- Verify the UIDIndex index function returns the UID for every object exactly once
- Never add two objects sharing a UID to a test indexer
When it happens
Trigger: wfc.wfInformer.GetIndexer().ByIndex(indexes.UIDIndex, uid) returned 2+ objects — duplicate entries in the informer cache for one UID, typically from a cache inconsistency, a bug in index bookkeeping, or non-standard cache seeding in tests.
Common situations: Informer cache corruption after reconnect storms to the API server; test harnesses adding the same UID under different names/namespaces; custom modifications of the UID index function.
Related errors
- object %+v is not an unstructured
- failed to get workflow by key after locking
- failed to get pod from informer store: %w
- failed to delete ConfigMap %s: %w
- failed to update ConfigMap %s: %w
AI-assisted analysis of argoproj/argo-workflows@35bff19146 (2026-09-03).
Data as JSON: /api/errors/b73be15df0441deb.
Report an issue: GitHub.