argoproj/argo-workflows · error

issuer empty

Error message

issuer empty

What it means

newSso validates the SSO configuration loaded from the argo-server ConfigMap before constructing the OIDC service. The very first check requires a non-empty Issuer; if sso.issuer is missing, it returns 'issuer empty'. The issuer URL is the root of the OIDC discovery endpoint, so without it no provider metadata can be fetched and SSO cannot function.

Source

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

func providerFactoryOIDC(ctx context.Context, issuer string) (providerInterface, error) {
	return oidc.NewProvider(ctx, issuer)
}

func New(ctx context.Context, c Config, secretsIf corev1.SecretInterface, baseHRef string, secure bool) (Interface, error) {
	return newSso(ctx, providerFactoryOIDC, c, secretsIf, baseHRef, secure)
}

func newSso(
	ctx context.Context,
	factory providerFactory,
	c Config,
	secretsIf corev1.SecretInterface,
	baseHRef string,
	secure bool,
) (Interface, error) {
	baseHRef = authcookie.NormalizePath(baseHRef)
	if c.Issuer == "" {
		return nil, fmt.Errorf("issuer empty")
	}
	if c.ClientID.Name == "" || c.ClientID.Key == "" {
		return nil, fmt.Errorf("clientID empty")
	}
	if c.ClientSecret.Name == "" || c.ClientSecret.Key == "" {
		return nil, fmt.Errorf("clientSecret empty")
	}
	clientSecretObj, err := secretsIf.Get(ctx, c.ClientSecret.Name, metav1.GetOptions{})
	if err != nil {
		return nil, err
	}

	// Create http client
	httpClientConfig := HTTPClientConfig{
		InsecureSkipVerify: c.InsecureSkipVerify,
		RootCA:             c.RootCA,
	}
	httpClient, err := createHTTPClient(httpClientConfig)

View on GitHub (pinned to 35bff19146)

Solutions

  1. Add `sso.issuer: https://<your-provider>/...` to the argo-server SSO ConfigMap (e.g. https://accounts.google.com, https://your-domain/dex) and restart argo-server
  2. Verify the ConfigMap name/key matches what argo-server mounts (`argo-server-sso` by default) and the YAML nesting is correct
  3. Check argo-server logs for the full config dump (HTTPClientConfig etc.) to confirm which sso.* keys were actually loaded

Example fix

# ConfigMap
# before
data:
  sso.clientId: ...
# after
data:
  sso.issuer: https://accounts.google.com
  sso.clientId: ...
Defensive patterns

Strategy: validation

Validate before calling

var cfg sso.Config
yaml.Unmarshal(cm.Data, &cfg) // after mapping keys like sso.issuer
if cfg.Issuer == "" {
    return errors.New("ConfigMap is missing sso.issuer")
}
resp, err := http.Get(strings.TrimSuffix(cfg.Issuer, "/") + "/.well-known/openid-configuration")

Type guard

func issuerConfigured(cfg sso.Config) bool { return cfg.Issuer != "" }

Try / catch

svc, err := sso.New(ctx, controller, mode, cm, secretsIf, baseHRef, secure)
if err != nil && strings.Contains(err.Error(), "issuer empty") {
    return fmt.Errorf("argo-server SSO ConfigMap lacks sso.issuer: %w", err)
}

Prevention

When it happens

Trigger: The argo-server SSO ConfigMap exists but lacks the `sso.issuer` key (or it is an empty string), and argo-server calls New → newSso during startup; also triggered in unit tests that construct Config without Issuer.

Common situations: Fresh SSO setup where the ConfigMap was created from an incomplete template; issuer key removed or misspelled (e.g. `issuer:` with no value or nested under the wrong YAML level); an IssuerAlias-only setup where the actual issuer was accidentally dropped.

Related errors


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