argoproj/argo-workflows · error

duplicate ClusterWorkflowTemplate found: %q

Error message

duplicate ClusterWorkflowTemplate found: %q

What it means

The offline client indexes ClusterWorkflowTemplates by name in a map. If the walked manifests contain two ClusterWorkflowTemplates with the same metadata.name, the store cannot resolve unambiguously, so newOfflineClient fails with this duplicate error.

Source

Thrown at pkg/apiclient/offline-client.go:68

	for _, basePath := range paths {
		err := file.WalkManifests(ctx, basePath, func(path string, bytes []byte) error {
			for _, pr := range common.ParseObjects(ctx, bytes, false) {
				obj, err := pr.Object, pr.Err
				if err != nil {
					return fmt.Errorf("failed to parse YAML from file %s: %w", path, err)
				}

				if obj == nil {
					continue // could not parse to kubernetes object
				}

				objName := obj.GetName()
				namespace := obj.GetNamespace()

				switch v := obj.(type) {
				case *wfv1.ClusterWorkflowTemplate:
					if _, ok := clusterWorkflowTemplateGetter.clusterWorkflowTemplates[objName]; ok {
						return fmt.Errorf("duplicate ClusterWorkflowTemplate found: %q", objName)
					}
					clusterWorkflowTemplateGetter.clusterWorkflowTemplates[objName] = v

				case *wfv1.WorkflowTemplate:
					getter, ok := workflowTemplateGetters[namespace]
					if !ok {
						getter = &offlineWorkflowTemplateNamespacedGetter{
							namespace:         namespace,
							workflowTemplates: map[string]*wfv1.WorkflowTemplate{},
						}
						workflowTemplateGetters[namespace] = getter
					}

					if _, ok := getter.(*offlineWorkflowTemplateNamespacedGetter).workflowTemplates[objName]; ok {
						return fmt.Errorf("duplicate WorkflowTemplate found: %q", objName)
					}
					getter.(*offlineWorkflowTemplateNamespacedGetter).workflowTemplates[objName] = v
				}

View on GitHub (pinned to 35bff19146)

Solutions

  1. Rename one of the duplicate ClusterWorkflowTemplates (metadata.name must be unique).
  2. Delete or exclude the stale duplicate file from the linted paths.
  3. Grep the walked paths for the offending name to find both definitions.

Example fix

// before
apiVersion: argoproj.io/v1alpha1
kind: ClusterWorkflowTemplate
metadata:
  name: my-template
// (same name in second file)
// after
metadata:
  name: my-template-v2
Defensive patterns

Strategy: validation

Validate before calling

func checkDupClusterTemplates(dir string) error {
    seen := map[string]bool{}
    return filepath.Walk(dir, func(p string, _ fs.FileInfo, err error) error {
        // parse docs, if kind==ClusterWorkflowTemplate:
        // if seen[name] { return fmt.Errorf("dup %s", name) }; seen[name]=true
        _ = seen
        return err
    })
}

Try / catch

if err != nil && strings.Contains(err.Error(), "duplicate ClusterWorkflowTemplate found") {
    // extract quoted name from err, grep manifests for that name
    return fmt.Errorf("remove or rename one of the duplicates: %w", err)
}

Prevention

When it happens

Trigger: Passing a set of paths to the offline client (e.g. `argo lint` with a directory) where two files, or two documents in one file, both define a ClusterWorkflowTemplate with the identical name.

Common situations: Copy-pasting a template into a second file and renaming only one; linting a directory that accumulates old versions of the same template; Helm/kustomize output that renders the same template twice.

Related errors


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