go-task/task · error
failed to read CA certificate: %w
Error message
failed to read CA certificate: %w
What it means
When --cacert is supplied, buildHTTPClient reads the CA bundle from disk with os.ReadFile. Any read failure (missing file, permission denied, path is a directory) is wrapped as "failed to read CA certificate" with the OS error.
Source
Thrown at taskfile/node_http.go:48
// 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()
if !caCertPool.AppendCertsFromPEM(caCertData) {
return nil, fmt.Errorf("failed to parse CA certificate")
}
tlsConfig.RootCAs = caCertPool
}
// Load client certificate and key if provided
if cert != "" && certKey != "" {
clientCert, err := tls.LoadX509KeyPair(cert, certKey)
if err != nil {
return nil, fmt.Errorf("failed to load client certificate: %w", err)
}
tlsConfig.Certificates = []tls.Certificate{clientCert}
}
return &http.Client{View on GitHub (pinned to 385e5ad92a)
Solutions
- Fix the --cacert path to point at an existing PEM file the user can read
- Ensure the CA bundle exists in the container/CI image (copy it in or install ca-certificates)
- Check permissions: chmod 644 the CA file if needed
- Look at the wrapped OS error in the message to distinguish not-found vs permission vs is-a-directory
Example fix
# before task --cacert /etc/ssl/certs -f https://internal.example.com/Taskfile.yml # after task --cacert /etc/ssl/certs/corp-root.pem -f https://internal.example.com/Taskfile.yml
Defensive patterns
Strategy: validation
Validate before calling
func caCertReadable(path string) error {
fi, err := os.Stat(path)
if err != nil {
return fmt.Errorf("cacert %s: %w", path, err)
}
if !fi.Mode().IsRegular() {
return fmt.Errorf("cacert %s is not a regular file", path)
}
f, err := os.Open(path)
if err != nil {
return fmt.Errorf("cacert %s unreadable: %w", path, err)
}
f.Close()
return nil
} Type guard
func isReadablePEMFile(path string) bool {
fi, err := os.Stat(path)
return err == nil && fi.Mode().IsRegular() && fi.Mode().Perm()&0o400 != 0
} Try / catch
node, err := taskfile.NewHTTPNode(..., caCert, ...)
if err != nil {
var pe *fs.PathError
if errors.As(err, &pe) && strings.Contains(err.Error(), "failed to read CA certificate") {
// correct path/permissions before retrying
}
return err
} Prevention
- Point --cacert at a single PEM bundle file, not a directory
- Verify the cert path exists in the exact container/CI image used
- Check file permissions for the user running task
- Commit or mount corporate CA bundles as part of environment setup
When it happens
Trigger: NewHTTPNode -> buildHTTPClient with a non-empty caCert string that os.ReadFile cannot read: nonexistent path, unreadable permissions, or a directory passed as the cert file.
Common situations: Pointing --cacert at a directory (like the system /etc/ssl/certs) instead of a PEM bundle file; typo in the cert path; container images missing the corporate CA bundle; permission-restricted certs in CI.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- failed to parse CA certificate
- both --cert and --cert-key must be provided together
- task: --cert and --cert-key must be provided together
- error reading env file %s: %w
- failed to load client certificate: %w
AI-assisted analysis of go-task/task@385e5ad92a (2026-09-05).
Data as JSON: /api/errors/2fcc55e417a4e948.
Report an issue: GitHub.