argoproj/argo-workflows · error
AuthSupplier cannot be empty when connecting to Argo Server
Error message
AuthSupplier cannot be empty when connecting to Argo Server
What it means
When connecting over HTTP1 to the Argo Server (opts.ArgoServerOpts.HTTP1, used for HTTP fallback / proxies / event streams), the client authenticates using a caller-supplied AuthSupplier. There is no default credential source in this mode, so a nil AuthSupplier is rejected rather than producing an unauthenticated client.
Source
Thrown at pkg/apiclient/apiclient.go:78
}
logFormat, err := logging.TypeFromStringOr(opts.LogFormat, logging.Text)
if err != nil {
return nil, nil, err
}
log = logging.NewSlogLogger(logLevel, logFormat)
ctx = logging.WithLogger(ctx, log)
}
log.WithField("opts", opts).Debug(ctx, "Client options")
if opts.Offline {
return newOfflineClient(ctx, opts.OfflineFiles)
}
if opts.ArgoServerOpts.URL != "" && opts.InstanceID != "" {
return nil, nil, fmt.Errorf("cannot use instance ID with Argo Server")
}
switch {
case opts.ArgoServerOpts.HTTP1:
if opts.AuthSupplier == nil {
return nil, nil, fmt.Errorf("AuthSupplier cannot be empty when connecting to Argo Server")
}
return newHTTP1Client(ctx, opts.ArgoServerOpts, opts.AuthSupplier(), opts.Proxy)
case opts.ArgoServerOpts.URL != "":
if opts.AuthSupplier == nil {
return nil, nil, fmt.Errorf("AuthSupplier cannot be empty when connecting to Argo Server")
}
return newArgoServerClient(ctx, opts.ArgoServerOpts, opts.AuthSupplier())
default:
if opts.ClientConfigSupplier != nil {
opts.ClientConfig = opts.ClientConfigSupplier()
}
return newArgoKubeClient(ctx, opts.ArgoKubeOpts, opts.ClientConfig, instanceid.NewService(opts.InstanceID))
}
}
View on GitHub (pinned to 35bff19146)
Solutions
- Set Opts.AuthSupplier to a func returning your auth token (e.g. () -> "Bearer <token>")
- If using the argo CLI, don't hand-build Opts — use the CLI's client factory which supplies auth automatically
- If you only need the gRPC path, clear HTTP1 and set URL with AuthSupplier or use ClientConfigSupplier for direct-kube
Example fix
// before
opts := apiclient.Opts{ArgoServerOpts: apiclient.ArgoServerOpts{URL: url, HTTP1: true}}
// after
opts := apiclient.Opts{ArgoServerOpts: apiclient.ArgoServerOpts{URL: url, HTTP1: true}, AuthSupplier: func() string { return token }} Defensive patterns
Strategy: validation
Validate before calling
func newHTTP1Opts(url, token string) (apiclient.Opts, error) {
if token == "" {
return apiclient.Opts{}, errors.New("token required for HTTP1 Argo Server access (set ARGO_TOKEN)")
}
return apiclient.Opts{
ArgoServerOpts: apiclient.ArgoServerOpts{URL: url, HTTP1: true},
AuthSupplier: func() string { return "Bearer " + token },
}, nil
} Prevention
- Check Opts.AuthSupplier != nil in a buildOpts helper before calling the library
- Load the token from ARGO_TOKEN or SSO in one shared factory
- Write an integration smoke test that constructs the client early at startup
When it happens
Trigger: NewClientFromOptsWithContext with Opts{ArgoServerOpts: {URL: ..., HTTP1: true}} and AuthSupplier nil — e.g. constructing Opts by hand without the wiring the CLI normally performs (which sets AuthSupplier from the k8s token/SSO).
Common situations: Custom Go programs using pkg/apiclient with HTTP1 enabled; environments where ARGO_TOKEN/auth wiring was skipped; testing HTTP1 mode directly without replicating the CLI's auth setup.
Related errors
- cannot use instance ID with Argo Server
- this is impossible if you are not using the Argo Server, see
- failure to create dynamic client: %w
- must specify at least one auth mode
- insufficient authentication information provided
AI-assisted analysis of argoproj/argo-workflows@35bff19146 (2026-09-03).
Data as JSON: /api/errors/0bdc6d098ac9fc87.
Report an issue: GitHub.