go-task/task · error

both --cert and --cert-key must be provided together

Error message

both --cert and --cert-key must be provided together

What it means

buildHTTPClient enforces that a TLS client certificate (--cert) and its key (--cert-key) are supplied as a pair. Providing exactly one of them is invalid because Go's tls.Config requires both to load a client certificate, so it errors before any HTTP request is made.

Source

Thrown at taskfile/node_http.go:32

	"github.com/go-task/task/v3/errors"
	"github.com/go-task/task/v3/internal/execext"
	"github.com/go-task/task/v3/internal/filepathext"
)

// An HTTPNode is a node that reads a Taskfile from a remote location via HTTP.
type HTTPNode struct {
	*baseNode
	url    *url.URL     // stores url pointing actual remote file. (e.g. with Taskfile.yml)
	client *http.Client // HTTP client with optional TLS configuration
}

// buildHTTPClient creates an HTTP client with optional TLS configuration.
// If no certificate options are provided, it returns http.DefaultClient.
func buildHTTPClient(insecure bool, caCert, cert, certKey string) (*http.Client, error) {
	// Validate that cert and certKey are provided together
	if (cert != "" && certKey == "") || (cert == "" && certKey != "") {
		return nil, fmt.Errorf("both --cert and --cert-key must be provided together")
	}

	// If no TLS customization is needed, return the default client
	if !insecure && caCert == "" && cert == "" {
		return http.DefaultClient, nil
	}

	tlsConfig := &tls.Config{
		InsecureSkipVerify: insecure, //nolint:gosec
	}

	// Load custom CA certificate if provided
	if caCert != "" {
		caCertData, err := os.ReadFile(caCert)
		if err != nil {
			return nil, fmt.Errorf("failed to read CA certificate: %w", err)
		}
		caCertPool := x509.NewCertPool()

View on GitHub (pinned to 385e5ad92a)

Solutions

  1. Pass both flags together: --cert client.crt --cert-key client.key
  2. If you don't need client certs, remove both flags entirely
  3. Check the config file/env that feeds these flags to ensure both values are set
  4. Regenerate or locate the missing key matching the certificate

Example fix

# before
task --cert ./client.crt -f https://example.com/Taskfile.yml
# after
task --cert ./client.crt --cert-key ./client.key -f https://example.com/Taskfile.yml
Defensive patterns

Strategy: validation

Validate before calling

if (cert == "") != (certKey == "") {
    return fmt.Errorf("--cert and --cert-key must be provided together")
}

Type guard

func hasCompleteClientCertPair(cert, certKey string) bool {
    return (cert == "") == (certKey == "")
}

Try / catch

node, err := taskfile.NewHTTPNode(..., cert, certKey, ...)
if err != nil {
    if strings.Contains(err.Error(), "must be provided together") {
        // surface flag guidance to the user or fall back to default client
    }
    return err
}

Prevention

When it happens

Trigger: NewHTTPNode -> buildHTTPClient called with cert set and certKey empty, or certKey set and cert empty — e.g. invoking task with --cert but forgetting --cert-key (or vice versa) when fetching a remote Taskfile over HTTPS.

Common situations: Mutual-TLS setups where a user passes the client cert but forgets the key path; flags wired from config where only one of the two values was populated; copy-pasting examples that set only one flag.

Related errors


AI-assisted analysis of go-task/task@385e5ad92a (2026-09-05). Data as JSON: /api/errors/31c9ebfa00081e45. Report an issue: GitHub.