argoproj/argo-workflows · error

invalid cache key: %s

Error message

invalid cache key: %s

What it means

When saving a memoization cache entry, the cache key must match cacheKeyRegex (a DNS-subdomain-like pattern). Keys that are too long (>253 chars) or contain invalid characters are rejected with this error, because ConfigMap keys/annotations cannot safely hold arbitrary strings.

Source

Thrown at workflow/controller/cache/configmap_cache.go:154

	err := retry.OnError(kwait.Backoff{
		Duration: time.Second,
		Factor:   2,
		Jitter:   0.1,
		Steps:    5,
		Cap:      30 * time.Second,
	}, func(err error) bool {
		return argoerr.IsTransientErr(ctx, err) || apierr.IsConflict(err)
	}, func() error {
		innerErr := c.save(ctx, key, nodeID, value)
		return innerErr
	})
	return err
}

func (c *configMapCache) save(ctx context.Context, key string, nodeID string, value *wfv1.Outputs) error {
	if !cacheKeyRegex.MatchString(key) {
		errString := fmt.Sprintf("invalid cache key: %s", key)
		err := errors.New(errString)
		c.logError(ctx, err, logging.Fields{"key": key}, errString)
		return err
	}

	c.lock.Lock()
	defer c.lock.Unlock()

	c.logInfo(ctx, logging.Fields{"key": key, "nodeID": nodeID}, "Saving ConfigMap cache entry")

	cache, err := c.kubeClient.CoreV1().ConfigMaps(c.namespace).Get(ctx, c.name, metav1.GetOptions{})
	if apierr.IsNotFound(err) || cache == nil {
		cache, err = c.kubeClient.CoreV1().ConfigMaps(c.namespace).Create(ctx, &apiv1.ConfigMap{
			ObjectMeta: metav1.ObjectMeta{
				Name: c.name,
			},
		}, metav1.CreateOptions{})
		if err != nil {
			c.logError(ctx, err, logging.Fields{"key": key, "nodeID": nodeID}, "Error saving to ConfigMap cache")

View on GitHub (pinned to 35bff19146)

Solutions

  1. Shorten the memoization key to <=253 chars and keep it to [a-z0-9] with '-'/'.' separators.
  2. Hash a long value into the key instead of embedding it, e.g. use sha256 of the input string.
  3. Check the template expression building the key for unexpected content (full URLs, paths).

Example fix

# before
memoization:
  key: config-{{workflow.parameters.configUrl}}
# after
memoization:
  key: config-{{=sprig.sha256sum(workflow.parameters.configUrl)}}
Defensive patterns

Strategy: validation

Validate before calling

import "regexp"
var cacheKeyRegex = regexp.MustCompile(`^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$`)
func validCacheKey(k string) bool {
    return len(k) <= 253 && cacheKeyRegex.MatchString(k)
}

Type guard

func isValidCacheKey(key string) bool {
    return len(key) <= 253 && regexp.MustCompile(`^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$`).MatchString(key)
}

Try / catch

if err := node.SaveOutput(...); err != nil && strings.Contains(err.Error(), "invalid cache key") {
    // recompute a shorter, DNS-safe key and retry
}

Prevention

When it happens

Trigger: Calling save() (via SaveStreamViaTempFile or the anonymous key-construction path) with a memoization `key` value that fails cacheKeyRegex — typically a key longer than 253 characters or containing illegal characters (spaces, slashes, uppercase-unsafe values, etc.).

Common situations: Users set `memoization.key` from template expressions that embed long IDs (image digests, URLs, git SHAs concatenated); keys with `/` or spaces; generated keys exceeding ConfigMap limits.

Related errors


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