apache/pulsar · error · RestException

%s's peer-clusters %s can't be part of replication-clusters

Error message

%s's peer-clusters %s can't be part of replication-clusters %s

What it means

Pulsar forbids a cluster's peer-clusters from also appearing in a namespace's replication-clusters, because replication to a peer would loop. The deprecated sync validatePeerClusterConflict computes the intersection of the cluster's peerClusterNames and the requested replicationClusters and throws 409 CONFLICT if any cluster appears in both sets.

Source

Thrown at pulsar-broker/src/main/java/org/apache/pulsar/broker/web/PulsarWebResource.java:429

     *
     * @param clusterName given cluster whose peer-clusters can't be present into replication-cluster list
     * @param replicationClusters replication-cluster list
     * @deprecated use {@link #validatePeerClusterConflictAsync(String, Set)} instead
     */
    @Deprecated
    protected void validatePeerClusterConflict(String clusterName, Set<String> replicationClusters) {
        try {
            ClusterData clusterData = clusterResources().getCluster(clusterName).orElseThrow(
                    () -> new RestException(Status.PRECONDITION_FAILED, "Invalid replication cluster " + clusterName));
            Set<String> peerClusters = clusterData.getPeerClusterNames();
            if (peerClusters != null && !peerClusters.isEmpty()) {
                Sets.SetView<String> conflictPeerClusters = Sets.intersection(peerClusters, replicationClusters);
                if (!conflictPeerClusters.isEmpty()) {
                    log.warn()
                            .attr("cluster", clusterName)
                            .attr("conflictingPeerClusters", conflictPeerClusters)
                            .log("Peer clusters can't be part of replication clusters");
                    throw new RestException(Status.CONFLICT,
                            String.format("%s's peer-clusters %s can't be part of replication-clusters %s", clusterName,
                                    conflictPeerClusters, replicationClusters));
                }
            }
        } catch (RestException re) {
            throw re;
        } catch (Exception e) {
            log.warn()
                    .attr("cluster", clusterName)
                    .exception(e)
                    .log("Failed to get cluster-data");
        }
    }

    protected CompletableFuture<Void> validatePeerClusterConflictAsync(String clusterName,
                                                                       Set<String> replicationClusters) {
        return clusterResources().getClusterAsync(clusterName)
                .thenAccept(data -> {

View on GitHub (pinned to 820761864e)

Solutions

  1. Remove the conflicting cluster names from the namespace's replication-clusters list
  2. Or remove them from the cluster's peerClusterNames (pulsar-admin clusters update) if peer relationships are stale
  3. Redesign topology: peer-clusters are for local service discovery among clusters sharing a namespace ownership; replication should use only non-peer clusters
  4. Migrate callers to validatePeerClusterConflictAsync — this sync method is deprecated

Example fix

// before
pulsar-admin namespaces set-clusters my-tenant/ns --clusters c1,c2  // c2 is peer of c1's cluster
// after: remove the peer conflict
pulsar-admin clusters update c1 --peer-cluster-names 
// then
pulsar-admin namespaces set-clusters my-tenant/ns --clusters c1,c2
Defensive patterns

Strategy: validation

Validate before calling

// Reject replication clusters that overlap the cluster's peers, before calling the API
ClusterData cd = admin.clusters().getCluster(clusterName);
Set<String> peers = cd.getPeerClusterNames() == null ? Set.of() : cd.getPeerClusterNames();
Set<String> conflict = new HashSet<>(peers); conflict.retainAll(replicationClusters);
if (!conflict.isEmpty()) throw new IllegalArgumentException("Conflicting peer clusters: " + conflict);

Prevention

When it happens

Trigger: Setting/updating a namespace's replication clusters (namespaces API, setReplicationClusters) or cluster data while the target cluster's ClusterData.peerClusterNames contains one of the requested replication clusters. The offending cluster names are printed in the message.

Common situations: Configuring geo-replication between two clusters that were already declared peers of each other; leftover peerClusterNames from a previous replication topology; automated tooling copying the same set into both peer-clusters and replication-clusters.

Related errors


AI-assisted analysis of apache/pulsar@820761864e (2026-09-06). Data as JSON: /api/errors/34ca3b23f0eb2fc7. Report an issue: GitHub.