argoproj/argo-workflows · error

if you have an item in your config map named 'config', you…

Error message

if you have an item in your config map named 'config', you must only have one item

What it means

parseConfigMap reads the workflow-controller-configmap. If a key literally named `config` exists, it must be the ONLY key, since `config` holds the entire YAML document while other keys are treated as individual top-level entries. Mixed usage is ambiguous, so it is rejected with this error.

Solutions

  1. Merge all configuration into the single `config` YAML key and delete the other keys from the configmap.
  2. Alternatively migrate fully to per-key entries (the non-`config` style) and remove the `config` key.
  3. Apply the corrected configmap with kubectl and let the controller reload it.
  4. Audit chart/tooling that writes extra keys into workflow-controller-configmap and pin them to one of the two accepted formats.

Example fix

// before
data:
  config: |
    containerRuntimeExecutor: emissary
  links: |
    ...
// after
data:
  config: |
    containerRuntimeExecutor: emissary
    links:
      - ...
Defensive patterns

Strategy: validation

Validate before calling

// validate configmap keys before apply
keys := listConfigMapKeys("workflow-controller-configmap")
if containsKey(keys, "config") && len(keys) > 1 {
    return errors.New("key 'config' must be the only key in the configmap")
}

Type guard

func isLegacySingleKeyConfig(cm *apiv1.ConfigMap) bool {
    _, ok := cm.Data["config"]
    return ok && len(cm.Data) == 1
}

Try / catch

cfg, err := config.Parse(ctx, cm)
if err != nil {
    return nil, fmt.Errorf("invalid workflow-controller-configmap (merge everything into one 'config' key or all separate keys): %w", err)
}

Prevention

When it happens

Trigger: The configmap contains a `config` key plus at least one other key (len(cm.Data) != 1) when Parse/parseConfigMap runs, e.g. during controller startup or config reload.

Common situations: Operators adding a new setting as a separate key while the legacy single `config` YAML key is still present; leftover keys from Helm charts or tooling writing extra entries (tls, secrets-style keys) into the same configmap.

Related errors


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

Appendix: source

Thrown at config/controller.go:43

	// name of the config map
	configMap     string
	kubeclientset kubernetes.Interface
}

func NewController(namespace, name string, kubeclientset kubernetes.Interface) Controller {
	return &controller{
		namespace:     namespace,
		configMap:     name,
		kubeclientset: kubeclientset,
	}
}

func parseConfigMap(cm *apiv1.ConfigMap, config *Config) error {
	// The key in the configmap to retrieve workflow configuration from.
	// Content encoding is expected to be YAML.
	rawConfig, ok := cm.Data["config"]
	if ok && len(cm.Data) != 1 {
		return fmt.Errorf("if you have an item in your config map named 'config', you must only have one item")
	}
	if !ok {
		for name, value := range cm.Data {
			if strings.Contains(value, "\n") {
				// this mucky code indents with two spaces
				rawConfig = rawConfig + name + ":\n  " + strings.Join(strings.Split(strings.Trim(value, "\n"), "\n"), "\n  ") + "\n"
			} else {
				rawConfig = rawConfig + name + ": " + value + "\n"
			}
		}
	}
	err := yaml.UnmarshalStrict([]byte(rawConfig), config)
	return err
}

func (cc *controller) Get(ctx context.Context) (*Config, error) {
	cmClient := cc.kubeclientset.CoreV1().ConfigMaps(cc.namespace)
	cm, err := cmClient.Get(ctx, cc.configMap, metav1.GetOptions{})

View on GitHub (pinned to 35bff19146)