temporalio/temporal · error

only one of caData or caFile properties should be specified

Error message

only one of caData or caFile properties should be specified

What it means

ConfigureCassandraCluster validates the Cassandra TLS config and rejects a config that specifies both inline CA certificate content (CaData) and a CA file path (CaFile). Only one CA source may be given so the SslOpts.RootCAs pool can be built deterministically. Thrown before any connection is attempted.

Source

Thrown at common/persistence/nosql/nosqlplugin/cassandra/gocql/client.go:69

		}
	}
	if cfg.Keyspace != "" {
		cluster.Keyspace = cfg.Keyspace
	}
	if cfg.Datacenter != "" {
		cluster.HostFilter = gocql.DataCentreHostFilter(cfg.Datacenter)
	}
	if cfg.TLS != nil && cfg.TLS.Enabled {
		if cfg.TLS.CertData != "" && cfg.TLS.CertFile != "" {
			return errors.New("only one of certData or certFile properties should be specified")
		}

		if cfg.TLS.KeyData != "" && cfg.TLS.KeyFile != "" {
			return errors.New("only one of keyData or keyFile properties should be specified")
		}

		if cfg.TLS.CaData != "" && cfg.TLS.CaFile != "" {
			return errors.New("only one of caData or caFile properties should be specified")
		}

		cluster.SslOpts = &gocql.SslOptions{
			CaPath:                 cfg.TLS.CaFile,
			EnableHostVerification: cfg.TLS.EnableHostVerification,
			Config:                 auth.NewTLSConfigForServer(cfg.TLS.ServerName, cfg.TLS.EnableHostVerification),
		}

		var certBytes []byte
		var keyBytes []byte
		var err error

		if cfg.TLS.CertFile != "" {
			certBytes, err = os.ReadFile(cfg.TLS.CertFile)
			if err != nil {
				return fmt.Errorf("error reading client certificate file: %w", err)
			}
		} else if cfg.TLS.CertData != "" {

View on GitHub (pinned to bde624efd1)

Solutions

  1. Remove either caData or caFile from the cassandra TLS config, keeping only one
  2. Prefer caFile when certs are mounted on disk; set caData to ""
  3. Prefer caData (base64-encoded PEM) when config is delivered via dynamicconfig; delete caFile

Example fix

// before
persistence:
  cassandra:
    tls:
      enabled: true
      caFile: /etc/certs/ca.pem
      caData: LS0tLS1CRUdJTiBDRVJUSUZ...
// after
persistence:
  cassandra:
    tls:
      enabled: true
      caData: LS0tLS1CRUdJTiBDRVJUSUZ...
Defensive patterns

Strategy: validation

Validate before calling

func validateTLSCA(tls config.TLS) error {
    if !tls.Enabled { return nil }
    if tls.CaData != "" && tls.CaFile != "" {
        return errors.New("specify only one of caData or caFile")
    }
    return nil
}

Prevention

When it happens

Trigger: Calling NewCassandraCluster with cfg.TLS.Enabled true and both cfg.TLS.CaData and cfg.TLS.CaFile non-empty.

Common situations: Cluster operators migrating from file-based certs to inline dynamicconfig values without deleting the old field; helm charts templating both values; accidental duplication when overriding config per environment.

Related errors


AI-assisted analysis of temporalio/temporal@bde624efd1 (2026-09-01). Data as JSON: /api/errors/2b377b18fb06ebde. Report an issue: GitHub.