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
- Merge all configuration into the single `config` YAML key and delete the other keys from the configmap.
- Alternatively migrate fully to per-key entries (the non-`config` style) and remove the `config` key.
- Apply the corrected configmap with kubectl and let the controller reload it.
- 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
- Pick one configmap format — single `config` YAML key OR per-key entries — and stick to it.
- Audit Helm charts/operator manifests for extra keys written into the configmap.
- Validate with `argo lint` or a dry-run before kubectl apply.
- Document the format in your deployment tooling to prevent drift.
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
- artifact driver not found
- memoization configmap doesn't have
- AlreadyExists
- cannot fetch workflow spec without workflowTemplateRef
- client certificate authentication requires both clientCert…
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)