{"record":{"id":"d73d0c92dd97a18b","repo":"apache/pulsar","slug":"partition-count-mismatch-for-topictype-topic","errorCode":null,"errorMessage":"Partition count mismatch for ${topicType} '${topic}': local cluster has ${localPartitions} partitions, remote cluster '${remoteCluster}' has ${remotePartitions} partitions. Please ensure partition counts are the same before enabling replication.","messagePattern":"Partition count mismatch for (.+?) '(.+?)': local cluster has (.+?) partitions, remote cluster '(.+?)' has (.+?) partitions\\. Please ensure partition counts are the same before enabling replication\\.","errorType":"http","errorClass":"RestException","httpStatus":409,"severity":"error","filePath":"pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/NamespacesBase.java","lineNumber":1149,"sourceCode":"                                    || ex instanceof PulsarAdminException.NotFoundException) {\n                                return Optional.empty();\n                            }\n                            throw new CompletionException(ex);\n                        });\n\n        return localMetadataFuture.thenCombine(remoteMetadataFuture, (localMetadataOpt, remoteMetadataOpt) -> {\n            // If topic doesn't exist on remote, validation passes\n            if (remoteMetadataOpt.isEmpty()) {\n                return null;\n            }\n\n            int localPartitions = localMetadataOpt.map(m -> m.partitions).orElse(0);\n            int remotePartitions = remoteMetadataOpt.get().partitions;\n\n            if (localPartitions != remotePartitions) {\n                String topicType = SystemTopicNames.isTopicPoliciesSystemTopic(topic)\n                        ? \"__change_events system topic\" : \"topic\";\n                throw new RestException(Status.CONFLICT,\n                        String.format(\"Partition count mismatch for %s '%s': local cluster has %d partitions, \"\n                                        + \"remote cluster '%s' has %d partitions. \"\n                                        + \"Please ensure partition counts are the same before enabling replication.\",\n                                topicType, topic, localPartitions, remoteCluster, remotePartitions));\n            }\n            return null;\n        });\n    }\n\n    /**\n     * Validates that the effective auto-topic creation policies are the same between local and remote clusters.\n     * The effective policy is computed by: namespace-level policy overrides broker-level if it exists.\n     */\n    private CompletableFuture<Void> validateAutoTopicCreationCompatibility(PulsarAdmin remoteAdmin,\n                                                                    String remoteCluster, Policies remoteNsPolicies) {\n        String namespaceStr = namespaceName.toString();\n\n        // Get local broker config","sourceCodeStart":1131,"sourceCodeEnd":1167,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/NamespacesBase.java#L1131-L1167","documentation":"This 409 CONFLICT is thrown during namespace replication validation when a system topic (e.g. the __change_events or topic-policies system topic) exists locally and on the remote cluster but with different partition counts. Geo-replication of namespace/system topics requires matching partition counts, so enabling or validating replication is refused.","triggerScenarios":"Enabling replication (or setting replication clusters) for a namespace whose system/partitioned topic has N partitions locally while the same topic on the remote cluster has M != N partitions.","commonSituations":"Topic was created with different defaultNumberOfBrokerPartitions on each cluster; an operator manually created the topic with createPartitionedTopic using different counts per cluster; bumping partitions on only one cluster (increasePartitions) before enabling replication.","solutions":["Compare partition counts on both clusters (GET /admin/v2/persistent/{tenant}/{ns}/{topic}/partitions) and recreate the topic on one cluster with the matching count","Delete and recreate the mismatched topic on the remote cluster with the local partition count before enabling replication","Align broker.conf defaultNumberOfBrokerPartitions across clusters so future topics match automatically","If it's a system topic, ensure both clusters run compatible Pulsar versions and the namespace policy that controls system topic partitions is identical"],"exampleFix":"// before: local 8 partitions, remote created with 4\n// remote cluster:\nadmin.topics().deletePartitionedTopic(\"persistent://my-tenant/my-ns/__change_events\");\nadmin.topics().createPartitionedTopic(\"persistent://my-tenant/my-ns/__change_events\", 8);\n// after: both clusters have 8 partitions, replication validation passes","handlingStrategy":"validation","validationCode":"int local = admin.topics().getPartitionedTopicMetadata(topic).partitions;\nint remote = remoteAdmin.topics().getPartitionedTopicMetadata(topic).partitions;\nif (local != remote) throw new IllegalStateException(\"Partition mismatch: \" + local + \" vs \" + remote);","typeGuard":null,"tryCatchPattern":"try {\n    admin.namespaces().setNamespaceReplicationClusters(ns, clusters);\n} catch (PulsarAdminException.ConflictException e) {\n    // reconcile topic partition counts across clusters\n}","preventionTips":["Keep defaultNumberOfBrokerPartitions identical across geo-cluster brokers","Always bump partitions on all clusters together","Verify system topic partitions match before enabling replication"],"tags":["conflict","replication","partitioned-topic","geo-replication"],"backgroundTag":"partition-count-mismatch","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"}