{"record":{"id":"ceaead60d235f746","repo":"apache/pulsar","slug":"peer-cluster-s-data-not-found","errorCode":null,"errorMessage":"Peer cluster %s data not found","messagePattern":"Peer cluster (.+?) data not found","errorType":"http","errorClass":"RestException","httpStatus":404,"severity":"error","filePath":"pulsar-broker/src/main/java/org/apache/pulsar/broker/web/PulsarWebResource.java","lineNumber":928,"sourceCode":"    private static CompletableFuture<ClusterDataImpl> getOwnerFromPeerClusterListAsync(PulsarService pulsar,\n            Set<String> replicationClusters, Set<String> allowedClusters) {\n        String currentCluster = pulsar.getConfiguration().getClusterName();\n        if (replicationClusters.isEmpty() && allowedClusters.isEmpty() || isBlank(currentCluster)) {\n            return CompletableFuture.completedFuture(null);\n        }\n\n        return pulsar.getPulsarResources().getClusterResources().getClusterAsync(currentCluster)\n                .thenCompose(cluster -> {\n                    if (!cluster.isPresent() || cluster.get().getPeerClusterNames() == null) {\n                        return CompletableFuture.completedFuture(null);\n                    }\n                    for (String peerCluster : cluster.get().getPeerClusterNames()) {\n                        if (replicationClusters.contains(peerCluster)\n                                || allowedClusters.contains(peerCluster)) {\n                            return pulsar.getPulsarResources().getClusterResources().getClusterAsync(peerCluster)\n                                    .thenApply(ret -> {\n                                        if (!ret.isPresent()) {\n                                            throw new RestException(Status.NOT_FOUND,\n                                                    \"Peer cluster \" + peerCluster + \" data not found\");\n                                        }\n                                        return (ClusterDataImpl) ret.get();\n                                    });\n                        }\n                    }\n                    return CompletableFuture.completedFuture(null);\n                }).exceptionally(ex -> {\n                    LOG.error()\n                            .attr(\"cluster\", currentCluster)\n                            .exceptionMessage(ex)\n                            .log(\"Failed to get peer-cluster -\");\n                    throw FutureUtil.wrapToCompletionException(ex);\n                });\n    }\n\n    protected static CompletableFuture<Void> checkAuthorizationAsync(PulsarService pulsarService, TopicName topicName,\n                        String role, String originalPrinciple, AuthenticationDataSource authenticationData,","sourceCodeStart":910,"sourceCodeEnd":946,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-broker/src/main/java/org/apache/pulsar/broker/web/PulsarWebResource.java#L910-L946","documentation":"HTTP 404 NOT_FOUND raised while validating peer-replication-cluster ownership: a namespace's peer cluster name is listed in peerClusterNames (or the allowed clusters), but no ClusterData record exists for that peer in the cluster configuration store. The broker cannot resolve the peer to route or authorize the request.","triggerScenarios":"Calling any endpoint that resolves namespace ownership where the namespace's cluster lists a peer cluster in peerClusterNames that was deleted from /admin/v2/clusters, or was never registered.","commonSituations":"A cluster was deregistered from the configuration store but namespaces still reference it in peerClusterNames; geo-replication setup partially completed; cluster renamed without updating peer lists.","solutions":["Register the missing peer cluster: PUT /admin/v2/clusters/<peerCluster> with valid ClusterData","Or remove the dangling peer cluster name from the cluster's peerClusterNames (update the owning cluster's config)","Audit all clusters' peerClusterNames against the actual cluster list to find stale references","If the namespace should no longer replicate to the peer, remove it from the namespace's replication_clusters"],"exampleFix":"// before: dangling peer reference\nadmin.clusters().updateCluster(\"west\", ClusterData.builder().peerClusterNames(Set.of(\"gone-east\")).build());\n// after: only reference registered clusters, or register the peer first\nadmin.clusters().createCluster(\"gone-east\", ClusterDataImpl.builder()\n    .serviceUrl(\"http://east.example.com:8080\").build());","handlingStrategy":"validation","validationCode":"Set<String> registered = admin.clusters().getClusters();\nfor (String peer : admin.clusters().getCluster(owner).getPeerClusterNames()) {\n    if (!registered.contains(peer)) throw new IllegalStateException(\"dangling peer cluster: \" + peer);\n}","typeGuard":"boolean peerClustersExist(ClusterData cd, Set<String> registered) {\n    return cd.getPeerClusterNames() == null || registered.containsAll(cd.getPeerClusterNames());\n}","tryCatchPattern":null,"preventionTips":["When deleting a cluster, first remove it from all peerClusterNames","Audit peerClusterNames vs actual clusters periodically","Script cluster deregistration to clean peer references"],"tags":["http-404","geo-replication","cluster-configuration","stale-config"],"backgroundTag":"stale-cluster-reference","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}