{"record":{"id":"da039fde5a99fc90","repo":"apache/pulsar","slug":"the-replication-cluster-does-not-provide-tls-encry","errorCode":null,"errorMessage":"The replication cluster does not provide TLS encrypted service","messagePattern":"The replication cluster does not provide TLS encrypted service","errorType":"http","errorClass":"RestException","httpStatus":412,"severity":"error","filePath":"pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/NamespacesBase.java","lineNumber":512,"sourceCode":"                                throw new RestException(Status.PRECONDITION_FAILED,\n                                    \"Cannot delete the global namespace \" + nsName + \". There are still more than \"\n                                    + \"one replication clusters configured or replication clusters is empty.\");\n                            }\n                            if (!cluster.equals(config().getClusterName())) {\n                                // the only replication cluster is other cluster, redirect\n                                return clusterResources().getClusterAsync(cluster)\n                                        .thenCompose(replClusterDataOpt -> {\n                                            ClusterData replClusterData = replClusterDataOpt\n                                                    .orElseThrow(() -> new RestException(Status.NOT_FOUND,\n                                                            \"Cluster \" + cluster + \" does not exist\"));\n                                            URL replClusterUrl;\n                                            try {\n                                                if (!replClusterData.isBrokerClientTlsEnabled()) {\n                                                    replClusterUrl = new URL(replClusterData.getServiceUrl());\n                                                } else if (StringUtils.isNotBlank(replClusterData.getServiceUrlTls())) {\n                                                    replClusterUrl = new URL(replClusterData.getServiceUrlTls());\n                                                } else {\n                                                    throw new RestException(Status.PRECONDITION_FAILED,\n                                                    \"The replication cluster does not provide TLS encrypted service\");\n                                                }\n                                            } catch (MalformedURLException checkedEx) {\n                                                throw new RestException(checkedEx);\n                                            }\n                                            URI redirect = UriBuilder.fromUri(uri.getRequestUri())\n                                                    .host(replClusterUrl.getHost())\n                                                    .port(replClusterUrl.getPort())\n                                                    .replaceQueryParam(\"authoritative\", false).build();\n                                                log.debug()\n                                                        .attr(\"redirect\", redirect)\n                                                        .attr(\"cluster\", cluster)\n                                                        .log(\"Redirecting the rest call\");\n                                                        throw new WebApplicationException(\n                                                                Response.temporaryRedirect(redirect)\n                                                                        .build());\n                                        });\n                            }","sourceCodeStart":494,"sourceCodeEnd":530,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/NamespacesBase.java#L494-L530","documentation":"A 412 PRECONDITION_FAILED thrown when deleting a global namespace whose sole remaining replication cluster is a different cluster: the broker tries to redirect the delete request to that cluster over TLS, but the remote cluster's cluster metadata has no serviceUrlTls configured. The delete cannot be forwarded securely, so it aborts.","triggerScenarios":"DELETE /admin/v2/namespaces/{tenant}/{namespace} on cluster A where the only remaining replication cluster B has brokerClientTlsEnabled=true but an empty/blank serviceUrlTls in its cluster metadata; the broker builds the redirect URL in precheckWhenDeleteNamespace and fails.","commonSituations":"Clusters configured with TLS-secured brokers but cluster metadata created before TLS was enabled, leaving serviceUrlTls blank; operators migrating clusters to HTTPS-only and forgetting to update cluster metadata; mixed TLS/non-TLS multi-cluster deployments.","solutions":["Update the remote cluster metadata to include a TLS service URL: PUT /admin/v2/clusters/{cluster} with serviceUrlTls set (e.g. https://broker:8443).","Alternatively set brokerClientTlsEnabled=false for that cluster metadata if the redirect should use the plain service URL (only if acceptable security-wise).","Delete the namespace directly on the owning cluster instead of being redirected.","Audit all cluster metadata entries with GET /admin/v2/clusters to confirm serviceUrlTls is populated wherever TLS is enabled."],"exampleFix":"// before\ncurl -X PUT http://broker:8080/admin/v2/clusters/cluster-b -d '{\"serviceUrl\":\"http://b:8080\",\"brokerClientTlsEnabled\":true}'\n\n// after\ncurl -X PUT http://broker:8080/admin/v2/clusters/cluster-b -d '{\"serviceUrl\":\"http://b:8080\",\"serviceUrlTls\":\"https://b:8443\",\"brokerClientTlsEnabled\":true}'","handlingStrategy":"validation","validationCode":"const clusterData = await admin.clusters().getCluster(remoteCluster);\nif (clusterData.brokerClientTlsEnabled && !clusterData.serviceUrlTls) {\n  throw new Error(`cluster ${remoteCluster} lacks serviceUrlTls; fix metadata before namespace delete`);\n}","typeGuard":null,"tryCatchPattern":"try {\n  await admin.namespaces().deleteNamespace(tenant, ns);\n} catch (e) {\n  if (e.getStatusCode() === 412 && /TLS/.test(e.getMessage())) {\n    // update cluster metadata with serviceUrlTls, then retry\n  } else throw e;\n}","preventionTips":["Populate serviceUrlTls in every cluster record where TLS is used","Audit cluster metadata after TLS migrations","Prefer deleting namespaces on the owning cluster to avoid redirect paths"],"tags":["pulsar","tls","geo-replication","cluster-configuration"],"backgroundTag":"missing-tls-service-url","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}