argoproj/argo-workflows · error

invalid expiry date in Kubeconfig. %w

Error message

invalid expiry date in Kubeconfig. %w

What it means

RefreshTokenIfExpired reads the 'expiry' field from the kubeconfig auth-provider config and parses it strictly as RFC3339. If the timestamp cannot be parsed, GetBearerToken cannot proceed because it cannot decide whether the token needs refreshing, so it fails with this wrapped error.

Source

Thrown at util/kubeconfig/kubeconfig.go:284

	}
	return before, after, true
}

func ReloadKubeConfig(explicitPath string) clientcmd.ClientConfig {
	loadingRules := clientcmd.NewDefaultClientConfigLoadingRules()
	loadingRules.DefaultClientConfig = &clientcmd.DefaultClientConfig
	loadingRules.ExplicitPath = explicitPath
	overrides := clientcmd.ConfigOverrides{}
	return clientcmd.NewInteractiveDeferredLoadingClientConfig(loadingRules, &overrides, os.Stdin)
}

func RefreshTokenIfExpired(restConfig *restclient.Config, explicitPath, curentToken string) (string, error) {
	if restConfig.AuthProvider != nil {
		timestr := restConfig.AuthProvider.Config["expiry"]
		if timestr != "" {
			t, err := time.Parse(time.RFC3339, timestr)
			if err != nil {
				return "", fmt.Errorf("invalid expiry date in Kubeconfig. %w", err)
			}
			if time.Now().After(t) {
				err = RefreshAuthToken(restConfig)
				if err != nil {
					return "", err
				}
				config := ReloadKubeConfig(explicitPath)
				restConfig, err = config.ClientConfig()
				if err != nil {
					return "", err
				}
				return restConfig.AuthProvider.Config["access-token"], nil
			}
		}
	}
	return curentToken, nil
}

View on GitHub (pinned to 35bff19146)

Solutions

  1. Fix the kubeconfig 'expiry' value to strict RFC3339 (e.g. 2026-09-03T12:00:00Z) with no space separator and a timezone.
  2. Regenerate credentials with the provider's login tool (e.g. gcloud auth login / kubectl oidc-login) so it rewrites a valid expiry.
  3. Remove the stale auth-provider block and switch to a token/exec-based credential that does not carry an expiry field.
  4. Use an explicit kubeconfig path (explicitPath) pointing to a known-good file via `argo auth kubeconfig`.

Example fix

# before
apiVersion: v1
users:
- name: me
  user:
    auth-provider:
      config:
        expiry: "2026-09-03 12:00:00"
# after
        expiry: "2026-09-03T12:00:00Z"
Defensive patterns

Strategy: validation

Validate before calling

func expiryIsValid(kcfg string) error {
    cfg, err := clientcmd.LoadFromFile(kcfg)
    if err != nil { return err }
    for _, u := range cfg.AuthInfos {
        if ap := u.AuthProvider; ap != nil {
            if t := ap.Config["expiry"]; t != "" {
                if _, err := time.Parse(time.RFC3339, t); err != nil {
                    return fmt.Errorf("user %q expiry %q is not RFC3339", u.Name, t)
                }
            }
        }
    }
    return nil
}

Try / catch

token, err := kubeconfig.RefreshTokenIfExpired(restConfig, path, token)
if err != nil && strings.Contains(err.Error(), "invalid expiry date") {
    // prompt re-login / regenerate kubeconfig before retrying
    return fmt.Errorf("kubeconfig auth-provider expiry malformed; rerun provider login: %w", err)
}

Prevention

When it happens

Trigger: A kubeconfig whose auth-provider entry has an 'expiry' value not in RFC3339 format (e.g. '2024-05-01 12:00:00', epoch seconds '1714521600', or a locale-formatted date), used when obtaining a bearer token for a delegated kube workflow.

Common situations: Hand-edited kubeconfigs; cloud auth plugins (gke/oidc/azure) writing non-RFC3339 expiry values or an Argo version parsing a format the provider changed; expired or malformed kubeconfig copied from another machine.

Related errors


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