argoproj/argo-workflows · error

key %s missing in secret %s

Error message

key %s missing in secret %s

What it means

After loading the client-id secret object, newSso reads the configured key (c.ClientID.Key) from its Data map. A nil value means the secret exists but does not contain that key, so the OAuth client cannot be configured; the error names both the key and the secret for direct debugging.

Source

Thrown at server/auth/sso/sso.go:213

		if !isSecretAlreadyExists {
			return nil, fmt.Errorf("failed to create secret: %w", err)
		}
	}
	secret, err := secretsIf.Get(ctx, secretName, metav1.GetOptions{})
	if err != nil {
		return nil, fmt.Errorf("failed to read secret: %w", err)
	}
	privateKey, err := x509.ParsePKCS1PrivateKey(secret.Data[cookieEncryptionPrivateKeySecretKey])
	if err != nil {
		if isSecretAlreadyExists {
			return nil, fmt.Errorf("failed to parse private key. If you have already defined a Secret named %s, delete it and retry: %w", secretName, err)
		}
		return nil, fmt.Errorf("failed to parse private key: %w", err)
	}

	clientID := clientIDObj.Data[c.ClientID.Key]
	if clientID == nil {
		return nil, fmt.Errorf("key %s missing in secret %s", c.ClientID.Key, c.ClientID.Name)
	}
	clientSecret := clientSecretObj.Data[c.ClientSecret.Key]
	if clientSecret == nil {
		return nil, fmt.Errorf("key %s missing in secret %s", c.ClientSecret.Key, c.ClientSecret.Name)
	}
	config := &oauth2.Config{
		ClientID:     string(clientID),
		ClientSecret: string(clientSecret),
		RedirectURL:  c.RedirectURL,
		Endpoint:     provider.Endpoint(),
		Scopes:       append(c.Scopes, oidc.ScopeOpenID),
	}
	idTokenVerifier := provider.Verifier(&oidc.Config{ClientID: config.ClientID})
	// The server both mints and verifies these tokens, so symmetric AEAD is
	// sufficient: encryption with A256GCM also authenticates, and go-jose v4
	// only permits encrypt-only JWTs with symmetric algorithms. Asymmetric
	// encryption needed a nested signature, which pushed the cookie over the
	// 4KB browser limit (https://github.com/argoproj/argo-workflows/issues/16744).

View on GitHub (pinned to 35bff19146)

Solutions

  1. kubectl -n argo get secret <name> -o yaml and confirm a data entry exactly matching the configured key (case-sensitive)
  2. Recreate the secret with the exact key names, e.g. kubectl create secret generic argo-sso --from-file=client-id=... --from-file=client-secret=...
  3. Align sso.clientId.key in the configmap with the actual secret key
  4. Ensure the value is non-empty

Example fix

# before
kubectl create secret generic argo-sso --from-file=clientid=./id
sso: {clientId: {name: argo-sso, key: client-id}}
# after
kubectl create secret generic argo-sso --from-file=client-id=./id
sso: {clientId: {name: argo-sso, key: client-id}}
Defensive patterns

Strategy: validation

Validate before calling

idSecret, err := secretsIf.Get(ctx, cfg.ClientID.Name, metav1.GetOptions{})
if err != nil { return err }
if _, ok := idSecret.Data[cfg.ClientID.Key]; !ok {
    return fmt.Errorf("secret %s lacks key %s expected by sso.clientId", cfg.ClientID.Name, cfg.ClientID.Key)
}

Try / catch

if _, err := sso.New(ctx, cfg, secretsIf, baseHRef, secure); err != nil {
    var missErr *fmt.Errorf // check message pattern
    if strings.Contains(err.Error(), "missing in secret") {
        return fmt.Errorf("fix secret key names to match sso.clientId.key: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: New() when the secret referenced by sso.clientId.name exists but its data has no entry matching sso.clientId.key (case-sensitive).

Common situations: Secret created with --from-file names that differ from the configured key; singular/plural or dash/underscore mismatches ('clientid' vs 'client-id'); YAML key typo; empty-string value (Go []byte(nil)).

Related errors


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