argoproj/argo-workflows · error
--client-certificate and --client-key must be provided toget
Error message
--client-certificate and --client-key must be provided together
What it means
NewAPIClient validates kubectl-style auth overrides before dialing the argo server. mTLS requires both a client certificate and its matching private key; supplying only one is guaranteed misconfiguration, so it fails fast with this error.
Source
Thrown at cmd/argo/commands/client/conn.go:66
cmd.PersistentFlags().StringVar(&instanceID, "instanceid", os.Getenv("ARGO_INSTANCEID"), "submit with a specific controller's instance id label. Default to the ARGO_INSTANCEID environment variable.")
// "-s" like kubectl
cmd.PersistentFlags().StringVarP(&ArgoServerOpts.URL, "argo-server", "s", os.Getenv("ARGO_SERVER"), "API server `host:port`. e.g. localhost:2746. Defaults to the ARGO_SERVER environment variable.")
cmd.PersistentFlags().StringVar(&ArgoServerOpts.Path, "argo-base-href", os.Getenv("ARGO_BASE_HREF"), "Path to use with HTTP client due to Base HREF. Defaults to the ARGO_BASE_HREF environment variable.")
cmd.PersistentFlags().BoolVar(&ArgoServerOpts.HTTP1, "argo-http1", os.Getenv("ARGO_HTTP1") == "true", "If true, use the HTTP client. Defaults to the ARGO_HTTP1 environment variable.")
cmd.PersistentFlags().StringSliceVarP(&ArgoServerOpts.Headers, "header", "H", []string{}, "Sets additional header to all requests made by Argo CLI. (Can be repeated multiple times to add multiple headers, also supports comma separated headers) Used only when either ARGO_HTTP1 or --argo-http1 is set to true.")
// "-e" for encrypted - like zip
cmd.PersistentFlags().BoolVarP(&ArgoServerOpts.Secure, "secure", "e", os.Getenv("ARGO_SECURE") != "false", "Whether or not the server is using TLS with the Argo Server. Defaults to the ARGO_SECURE environment variable.")
// "-k" like curl
cmd.PersistentFlags().BoolVarP(&ArgoServerOpts.InsecureSkipVerify, "insecure-skip-verify", "k", os.Getenv("ARGO_INSECURE_SKIP_VERIFY") == "true", "If true, the Argo Server's certificate will not be checked for validity. This will make your HTTPS connections insecure. Defaults to the ARGO_INSECURE_SKIP_VERIFY environment variable.")
}
func NewAPIClient(ctx context.Context) (context.Context, apiclient.Client, error) {
// Reuse the explicit kubectl client certificate flags in server mode.
ArgoServerOpts.ClientCert = overrides.AuthInfo.ClientCertificate
ArgoServerOpts.ClientKey = overrides.AuthInfo.ClientKey
ArgoServerOpts.CACert = overrides.ClusterInfo.CertificateAuthority
if (ArgoServerOpts.ClientCert == "") != (ArgoServerOpts.ClientKey == "") {
return nil, nil, errors.New("--client-certificate and --client-key must be provided together")
}
var proxy func(*http.Request) (*url.URL, error)
if overrides.ClusterInfo.ProxyURL != "" {
proxyURL, err := url.Parse(overrides.ClusterInfo.ProxyURL)
if err != nil {
return nil, nil, err
}
proxy = http.ProxyURL(proxyURL)
}
return apiclient.NewClientFromOptsWithContext(ctx,
apiclient.Opts{
ArgoServerOpts: ArgoServerOpts,
InstanceID: instanceID,
AuthSupplier: func() string {
authString, err := GetAuthString(ctx)
if err != nil {
logger := logging.RequireLoggerFromContext(ctx)View on GitHub (pinned to 35bff19146)
Solutions
- Pass both flags together: --client-certificate /path/tls.crt --client-key /path/tls.key.
- Fix the kubeconfig user entry so client-certificate-data and client-key-data are both present.
- If the server doesn't require client certs, remove both flags and authenticate another way (token, SSO).
Example fix
// before argo list --client-certificate tls.crt // after argo list --client-certificate tls.crt --client-key tls.key
Defensive patterns
Strategy: validation
Validate before calling
if [ -n "$CLIENT_CERT" ] || [ -n "$CLIENT_KEY" ]; then
[ -n "$CLIENT_CERT" ] && [ -n "$CLIENT_KEY" ] || { echo 'need both cert and key'; exit 1; }
fi Try / catch
if ! argo list --client-certificate "$c" --client-key "$k" 2>err.txt; then grep -q 'must be provided together' err.txt && echo 'fix mTLS flags' fi
Prevention
- Always pass --client-certificate and --client-key as a pair.
- Keep both files in the same directory and rotate them together.
- Validate the kubeconfig user entry has both cert and key data.
When it happens
Trigger: Setting --client-certificate without --client-key (or vice versa) on any argo CLI command, or having only one of client-certificate-data/client-key-data in the kubeconfig user entry.
Common situations: Copying kubectl config examples that only set the cert; rotating certificates and replacing only one file; shell scripts where one flag is conditionally added.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- request failed with: %w
- failed to parse certificate: %w
- failed to read certificate file: %w
- requires either selector or workflow
- Multiple archived workflows found with name '%s': %s (Crea
AI-assisted analysis of argoproj/argo-workflows@35bff19146 (2026-09-03).
Data as JSON: /api/errors/49167b3f26ac3e49.
Report an issue: GitHub.