{"record":{"id":"2b377b18fb06ebde","repo":"temporalio/temporal","slug":"only-one-of-cadata-or-cafile-properties-should-be","errorCode":null,"errorMessage":"only one of caData or caFile properties should be specified","messagePattern":"only one of caData or caFile properties should be specified","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"common/persistence/nosql/nosqlplugin/cassandra/gocql/client.go","lineNumber":69,"sourceCode":"\t\t}\n\t}\n\tif cfg.Keyspace != \"\" {\n\t\tcluster.Keyspace = cfg.Keyspace\n\t}\n\tif cfg.Datacenter != \"\" {\n\t\tcluster.HostFilter = gocql.DataCentreHostFilter(cfg.Datacenter)\n\t}\n\tif cfg.TLS != nil && cfg.TLS.Enabled {\n\t\tif cfg.TLS.CertData != \"\" && cfg.TLS.CertFile != \"\" {\n\t\t\treturn errors.New(\"only one of certData or certFile properties should be specified\")\n\t\t}\n\n\t\tif cfg.TLS.KeyData != \"\" && cfg.TLS.KeyFile != \"\" {\n\t\t\treturn errors.New(\"only one of keyData or keyFile properties should be specified\")\n\t\t}\n\n\t\tif cfg.TLS.CaData != \"\" && cfg.TLS.CaFile != \"\" {\n\t\t\treturn errors.New(\"only one of caData or caFile properties should be specified\")\n\t\t}\n\n\t\tcluster.SslOpts = &gocql.SslOptions{\n\t\t\tCaPath:                 cfg.TLS.CaFile,\n\t\t\tEnableHostVerification: cfg.TLS.EnableHostVerification,\n\t\t\tConfig:                 auth.NewTLSConfigForServer(cfg.TLS.ServerName, cfg.TLS.EnableHostVerification),\n\t\t}\n\n\t\tvar certBytes []byte\n\t\tvar keyBytes []byte\n\t\tvar err error\n\n\t\tif cfg.TLS.CertFile != \"\" {\n\t\t\tcertBytes, err = os.ReadFile(cfg.TLS.CertFile)\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"error reading client certificate file: %w\", err)\n\t\t\t}\n\t\t} else if cfg.TLS.CertData != \"\" {","sourceCodeStart":51,"sourceCodeEnd":87,"githubUrl":"https://github.com/temporalio/temporal/blob/bde624efd13fbd3843654058db6d9c716166318b/common/persistence/nosql/nosqlplugin/cassandra/gocql/client.go#L51-L87","documentation":"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.","triggerScenarios":"Calling NewCassandraCluster with cfg.TLS.Enabled true and both cfg.TLS.CaData and cfg.TLS.CaFile non-empty.","commonSituations":"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.","solutions":["Remove either caData or caFile from the cassandra TLS config, keeping only one","Prefer caFile when certs are mounted on disk; set caData to \"\"","Prefer caData (base64-encoded PEM) when config is delivered via dynamicconfig; delete caFile"],"exampleFix":"// before\npersistence:\n  cassandra:\n    tls:\n      enabled: true\n      caFile: /etc/certs/ca.pem\n      caData: LS0tLS1CRUdJTiBDRVJUSUZ...\n// after\npersistence:\n  cassandra:\n    tls:\n      enabled: true\n      caData: LS0tLS1CRUdJTiBDRVJUSUZ...\n","handlingStrategy":"validation","validationCode":"func validateTLSCA(tls config.TLS) error {\n    if !tls.Enabled { return nil }\n    if tls.CaData != \"\" && tls.CaFile != \"\" {\n        return errors.New(\"specify only one of caData or caFile\")\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Standardize on caFile for mounted secrets or caData for dynamicconfig, not both","Add a config lint step validating TLS fields before deploy","When migrating between the two, explicitly delete the old field rather than leaving it populated"],"tags":["cassandra","tls","configuration"],"backgroundTag":"mutually-exclusive-config-options","analyzedSha":"bde624efd13fbd3843654058db6d9c716166318b","analyzedAt":"2026-09-01T07:18:39.080Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}