{"record":{"id":"c4696c4989dc48b5","repo":"t8y2/dbx","slug":"both-client-cert-path-and-client-key-path-are-requ","errorCode":null,"errorMessage":"both client_cert_path and client_key_path are required for IoTDB mTLS","messagePattern":"both client_cert_path and client_key_path are required for IoTDB mTLS","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"agents/drivers/iotdb/driver.go","lineNumber":210,"sourceCode":"\tif len(config.NodeURLs) == 0 {\n\t\tconfig.NodeURLs = []string{net.JoinHostPort(config.Host, strconv.Itoa(config.Port))}\n\t}\n\n\ttlsEnabled := params.SSL || queryBool(query, \"ssl\", \"useSSL\", \"use_ssl\", \"tls\")\n\tif tlsEnabled {\n\t\tconfig.TLSInsecureSkipVerify = queryBool(query, \"insecure_skip_verify\", \"tls_insecure_skip_verify\")\n\t\tconfig.TLSConfig = &client.TLSConfig{\n\t\t\tConfig: &tls.Config{\n\t\t\t\tServerName:         config.Host,\n\t\t\t\tMinVersion:         tls.VersionTLS12,\n\t\t\t\tInsecureSkipVerify: config.TLSInsecureSkipVerify,\n\t\t\t},\n\t\t\tCAFile:   strings.TrimSpace(params.CACertPath),\n\t\t\tCertFile: strings.TrimSpace(params.ClientCertPath),\n\t\t\tKeyFile:  strings.TrimSpace(params.ClientKeyPath),\n\t\t}\n\t\tif (config.TLSConfig.CertFile == \"\") != (config.TLSConfig.KeyFile == \"\") {\n\t\t\treturn connectionConfig{}, errors.New(\"both client_cert_path and client_key_path are required for IoTDB mTLS\")\n\t\t}\n\t}\n\treturn config, nil\n}\n\nfunc newSessionClient(config connectionConfig) (*sessionClient, error) {\n\tvar session client.Session\n\tvar err error\n\t// DBX applies a table database with USE after switching dialects. Do not\n\t// include a tree database in openSession: IoTDB 2.x rejects it there, while\n\t// DBX still retains it for metadata and path qualification.\n\tif len(config.NodeURLs) > 1 {\n\t\tsession, err = client.NewClusterSession(&client.ClusterConfig{\n\t\t\tNodeUrls:        config.NodeURLs,\n\t\t\tUserName:        config.Username,\n\t\t\tPassword:        config.Password,\n\t\t\tFetchSize:       config.FetchSize,\n\t\t\tTimeZone:        config.TimeZone,","sourceCodeStart":192,"sourceCodeEnd":228,"githubUrl":"https://github.com/t8y2/dbx/blob/c0390bff16418b651f4728520d99adf8ce48829a/agents/drivers/iotdb/driver.go#L192-L228","documentation":"parseConnectionConfig validates IoTDB mTLS settings and requires client_cert_path and client_key_path to be set together. If exactly one is provided, the config is incomplete and the driver rejects it.","triggerScenarios":"Enabling TLS with only client_cert_path or only client_key_path set (after trimming whitespace); a typo in one of the two parameter names so only one resolves.","commonSituations":"Partial migration from one-way TLS to mTLS; config templates with placeholders filled inconsistently; misspelled key names in connection strings/env vars.","solutions":["Set both client_cert_path and client_key_path to valid PEM file paths in the connection parameters.","If mTLS is not intended, remove the lone client_cert_path/client_key_path parameter so one-way TLS (CA only) is used.","Print/inspect the parsed params (e.g. log config.TLSConfig) to confirm both fields resolve; check for typos like client_cert or clientkey_path."],"exampleFix":"// before\nparams: ca_cert_path=/ca.pem client_cert_path=/client.crt\n// after\nparams: ca_cert_path=/ca.pem client_cert_path=/client.crt client_key_path=/client.key","handlingStrategy":"validation","validationCode":"func validateMTLSParams(params map[string]string) error {\n\tcert, key := params[\"client_cert_path\"], params[\"client_key_path\"]\n\tif (cert != \"\") != (key != \"\") {\n\t\treturn errors.New(\"client_cert_path and client_key_path must be set together\")\n\t}\n\treturn nil\n}","typeGuard":"func mTLSConfigComplete(tlsCfg TLSConfig) bool { return tlsCfg.CertFile != \"\" && tlsCfg.KeyFile != \"\" }","tryCatchPattern":"cfg, err := parseConnectionConfig(params)\nif err != nil {\n\tif strings.Contains(err.Error(), \"client_cert_path and client_key_path\") {\n\t\treturn fmt.Errorf(\"mTLS needs both files: set client_cert_path and client_key_path (got cert=%q key=%q)\", params[\"client_cert_path\"], params[\"client_key_path\"])\n\t}\n\treturn err\n}","preventionTips":["Use a config checklist/template that fills cert and key together.","Validate both files exist on disk before constructing the connection string.","Prefer a single mTLS toggle that requires both paths, rather than independent optional params."],"tags":["tls","mtls","configuration","iotdb","validation"],"backgroundTag":"incomplete-mtls-configuration","analyzedSha":"c0390bff16418b651f4728520d99adf8ce48829a","analyzedAt":"2026-09-05T23:05:10.900Z","contentChangedAt":"2026-09-05T23:05:10.900Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}