{"record":{"id":"86fc6f468549a2e4","repo":"hyperledger/fabric","slug":"chaincode-tls-root-cert-not-provided","errorCode":null,"errorMessage":"chaincode tls root cert not provided","messagePattern":"chaincode tls root cert not provided","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/container/externalbuilder/instance.go","lineNumber":101,"sourceCode":"\tconnInfo.ClientConfig.DialTimeout = time.Duration(c.DialTimeout)\n\tif connInfo.ClientConfig.DialTimeout == 0 {\n\t\tconnInfo.ClientConfig.DialTimeout = DialTimeout\n\t}\n\n\t// we can expose this if necessary\n\tconnInfo.ClientConfig.KaOpts = comm.DefaultKeepaliveOptions\n\n\tif !c.TLSRequired {\n\t\treturn connInfo, nil\n\t}\n\tif c.ClientAuthRequired && c.ClientKey == \"\" {\n\t\treturn nil, errors.New(\"chaincode tls key not provided\")\n\t}\n\tif c.ClientAuthRequired && c.ClientCert == \"\" {\n\t\treturn nil, errors.New(\"chaincode tls cert not provided\")\n\t}\n\tif c.RootCert == \"\" {\n\t\treturn nil, errors.New(\"chaincode tls root cert not provided\")\n\t}\n\n\tconnInfo.ClientConfig.SecOpts.UseTLS = true\n\n\tif c.ClientAuthRequired {\n\t\tconnInfo.ClientConfig.SecOpts.RequireClientCert = true\n\t\tconnInfo.ClientConfig.SecOpts.Certificate = []byte(c.ClientCert)\n\t\tconnInfo.ClientConfig.SecOpts.Key = []byte(c.ClientKey)\n\t\tconnInfo.ClientConfig.SecOpts.ServerNameOverride = c.Domain\n\t}\n\n\tconnInfo.ClientConfig.SecOpts.ServerRootCAs = [][]byte{[]byte(c.RootCert)}\n\n\treturn connInfo, nil\n}\n\nfunc (i *Instance) ChaincodeServerReleaseDir() string {\n\treturn filepath.Join(i.ReleaseDir, CCServerReleaseDir)","sourceCodeStart":83,"sourceCodeEnd":119,"githubUrl":"https://github.com/hyperledger/fabric/blob/2736b63f8fd5932511d56fe68b7039d15977f7f6/core/container/externalbuilder/instance.go#L83-L119","documentation":"Even without client auth, a TLS connection to the chaincode server needs the chaincode's root CA certificate to verify the server; connection.json without `root_cert` leaves the peer unable to trust the chaincode endpoint.","triggerScenarios":"connection.json sets tls_required true (client auth not required) but `root_cert` is empty when ChaincodeServerInfo sets SecOpts.UseTLS.","commonSituations":"TLS enabled on the chaincode but the CA cert not copied into the release dir; self-signed cert generated but never published; field misnamed in connection.json.","solutions":["Set `root_cert` in connection.json to the PEM-encoded CA/root certificate that signs the chaincode's server cert","Ensure the release script copies the root cert into the release directory","If TLS is not intended, set tls_required false in connection.json"],"exampleFix":"// before\n{\"tls_required\":true,\"address\":\"cc:7052\"}\n// after\n{\"tls_required\":true,\"address\":\"cc:7052\",\"root_cert\":\"root.pem\"}","handlingStrategy":"validation","validationCode":"var ud ChaincodeServerUserData\njson.Unmarshal(connJSON, &ud)\nif ud.TLSRequired && ud.RootCert == \"\" {\n    return errors.New(\"root_cert PEM required when tls_required is true\")\n}\nif block, _ := pem.Decode([]byte(ud.RootCert)); block == nil {\n    return errors.New(\"root_cert is not PEM encoded\")\n}","typeGuard":null,"tryCatchPattern":"info, err := ud.ChaincodeServerInfo(cryptoDir)\nif err != nil && strings.Contains(err.Error(), \"root cert not provided\") {\n    return fmt.Errorf(\"provide root_cert (CA of the chaincode server cert) or set tls_required=false: %w\", err)\n}","preventionTips":["Copy the chaincode CA cert into the release dir whenever TLS is enabled","Use a stable crypto dir layout so root_cert paths are predictable","Toggle tls_required consistently between chaincode config and connection.json"],"tags":["tls","certificates","chaincode-as-a-service","missing-field"],"backgroundTag":"missing-tls-credential","analyzedSha":"2736b63f8fd5932511d56fe68b7039d15977f7f6","analyzedAt":"2026-09-04T08:52:36.465Z","contentChangedAt":"2026-09-04T08:52:36.465Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}