argoproj/argo-workflows · error
if you have an item in your config map named 'config', you m
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.
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)
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
- memoization configmap doesn't have %s label, refusing to use
- artifact driver %s not found
- invalid TTL
- single branch mode without a branch specified
- failed to unmarshal container args: %w
AI-assisted analysis of argoproj/argo-workflows@35bff19146 (2026-09-03).
Data as JSON: /api/errors/b91df51cb2e7f778.
Report an issue: GitHub.