argoproj/argo-workflows · error
failed to get token secret "%s": %w
Error message
failed to get token secret "%s": %w
What it means
After resolving the ServiceAccount, the interceptor fetches its token Secret (name derived via TokenNameForServiceAccount, typically `<sa-name>-token`). This error wraps the Kubernetes Get failure, so the webhook cannot be authorized with the SA's bearer token. Note the format argument passed is the secret variable's value at that point, which is the secret name string.
Source
Thrown at server/auth/webhook/interceptor.go:107
serviceAccountInterface := kube.CoreV1().ServiceAccounts(namespace)
for serviceAccountName, data := range webhookClients.Data {
r.Body = io.NopCloser(bytes.NewBuffer(buf))
client := &webhookClient{}
err := yaml.Unmarshal(data, client)
if err != nil {
return fmt.Errorf("failed to unmarshal webhook client \"%s\": %w", serviceAccountName, err)
}
i.logger.WithFields(logging.Fields{"serviceAccountName": serviceAccountName, "webhookType": client.Type}).Debug(r.Context(), "Attempting to match webhook request")
ok := webhookParsers[client.Type](client.Secret, r)
if ok {
i.logger.WithField("serviceAccountName", serviceAccountName).Debug(r.Context(), "Matched webhook request")
serviceAccount, err := serviceAccountInterface.Get(ctx, serviceAccountName, metav1.GetOptions{})
if err != nil {
return fmt.Errorf("failed to get service account \"%s\": %w", serviceAccountName, err)
}
tokenSecret, err := secretsInterface.Get(ctx, secrets.TokenNameForServiceAccount(serviceAccount), metav1.GetOptions{})
if err != nil {
return fmt.Errorf("failed to get token secret \"%s\": %w", tokenSecret, err)
}
r.Header["Authorization"] = []string{"Bearer " + string(tokenSecret.Data["token"])}
return nil
}
}
return nil
}
View on GitHub (pinned to 35bff19146)
Solutions
- Check the secret exists: `kubectl get secret <sa-name>-token -n <namespace>`; if missing and on k8s >=1.24, create a long-lived token Secret (type kubernetes.io/service-account-token with kubernetes.io/service-account-name annotation) or a bound token.
- Confirm argo-server RBAC grants `get secrets` in the namespace.
- Recreate the ServiceAccount to regenerate a token secret on older clusters.
- If using projected tokens is intentional, this legacy webhook-auth path requires a static token secret — provision one manually.
- Read the wrapped error in server logs to separate NotFound from Forbidden.
Example fix
# k8s >=1.24: create a static token secret for the SA
apiVersion: v1
kind: Secret
metadata:
name: my-sa-token
namespace: <ns>
annotations:
kubernetes.io/service-account.name: my-sa
type: kubernetes.io/service-account-token Defensive patterns
Strategy: validation
Validate before calling
sa, _ := clientset.CoreV1().ServiceAccounts(ns).Get(ctx, saName, metav1.GetOptions{})
tokName := saName + "-token"
if _, err := clientset.CoreV1().Secrets(ns).Get(ctx, tokName, metav1.GetOptions{}); err != nil {
return fmt.Errorf("token secret %q missing for SA: %w", tokName, err)
} Try / catch
secret, err := clientset.CoreV1().Secrets(ns).Get(ctx, secrets.TokenNameForServiceAccount(sa), metav1.GetOptions{})
if errors.IsNotFound(err) {
// k8s >=1.24: create a static service-account-token Secret
} else if err != nil {
// check RBAC get secrets
} Prevention
- On k8s >=1.24 explicitly create a long-lived token Secret per webhook SA
- Grant argo-server `get secrets` in webhook namespaces
- Exclude `<sa>-token` secrets from secret-cleanup jobs
- Alert on missing token secrets for SAs referenced in webhook-clients
When it happens
Trigger: The matched ServiceAccount exists but its token Secret was deleted (common after Kubernetes 1.24+, where tokens are no longer auto-created as Secrets and are projected instead), or RBAC blocks reading secrets, or the secret lives in a different namespace.
Common situations: Cluster upgraded from k8s <=1.23 to >=1.24: legacy `<sa>-token` secrets no longer auto-created; TokenController disabled; argo-server RBAC missing `get secrets`; secret manually cleaned up by a secret-sweeper job.
Related errors
- failed to get service account "%s": %w
- failed to get service account secret: %w
- failed to create secret: %w
- failed to read secret: %w
- failed to parse private key. If you have already defined a S
AI-assisted analysis of argoproj/argo-workflows@35bff19146 (2026-09-03).
Data as JSON: /api/errors/8b5150e9bf37077a.
Report an issue: GitHub.