{"record":{"id":"d355afee2f1816de","repo":"apache/pulsar","slug":"number-of-transaction-coordinators-should-be-more","errorCode":null,"errorMessage":"Number of transaction coordinators should be more than the current number of transaction coordinator","messagePattern":"Number of transaction coordinators should be more than the current number of transaction coordinator","errorType":"http","errorClass":"RestException","httpStatus":406,"severity":"warning","filePath":"pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/TransactionsBase.java","lineNumber":550,"sourceCode":"            this.topicName = TopicName.get(TopicDomain.persistent.toString(), namespaceName, topic);\n        } catch (IllegalArgumentException e) {\n            log.warn()\n                    .attr(\"domain\", domain())\n                    .attr(\"tenant\", tenant)\n                    .attr(\"namespace\", namespace)\n                    .attr(\"topic\", topic)\n                    .exception(e)\n                    .log(\"Failed to validate topic name\");\n            throw new RestException(Response.Status.PRECONDITION_FAILED, \"Topic name is not valid\");\n        }\n    }\n\n    protected CompletableFuture<Void> internalScaleTransactionCoordinators(int replicas) {\n        return validateSuperUserAccessAsync()\n                .thenCompose((ignore) -> namespaceResources().getPartitionedTopicResources()\n                        .updatePartitionedTopicAsync(SystemTopicNames.TRANSACTION_COORDINATOR_ASSIGN, p -> {\n                            if (p.partitions >= replicas) {\n                                throw new RestException(Response.Status.NOT_ACCEPTABLE,\n                                        \"Number of transaction coordinators should \"\n                                                + \"be more than the current number of transaction coordinator\");\n                            }\n                            return new PartitionedTopicMetadata(replicas);\n                        }));\n    }\n\n    protected CompletableFuture<PositionInPendingAckStats> internalGetPositionStatsPendingAckStats(\n            boolean authoritative, String subName, Position position, Integer batchIndex) {\n        CompletableFuture<PositionInPendingAckStats> completableFuture = new CompletableFuture<>();\n        getExistingPersistentTopicAsync(authoritative)\n                .thenAccept(topic -> {\n                    PositionInPendingAckStats result = topic.getSubscription(subName)\n                    .checkPositionInPendingAckState(position, batchIndex);\n                    completableFuture.complete(result);\n                }).exceptionally(ex -> {\n                    completableFuture.completeExceptionally(ex);\n                    return null;","sourceCodeStart":532,"sourceCodeEnd":568,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/TransactionsBase.java#L532-L568","documentation":"Thrown by the broker admin API when scaling up transaction coordinators via internalScaleTransactionCoordinators. The partitioned topic that stores coordinator assignments (persistent://pulsar/system/transaction_coordinator_assign) already has at least as many partitions as the requested replica count. The scale operation only supports increasing the count, so a request that does not grow the partition count is rejected with HTTP 406 NOT_ACCEPTABLE.","triggerScenarios":"PUT/POST to the transaction-coordinator scale admin endpoint (internalScaleTransactionCoordinators) with replicas <= the current partition count of the transaction_coordinator_assign partitioned topic — e.g. calling scaleTransactionCoordinatorCount(4) when 4 coordinators already exist, or re-submitting the same value.","commonSituations":"Automation/idempotent deploy scripts that re-apply a desired coordinator count on every run; operators unaware the endpoint only scales up (no shrink supported); copying a config value from another cluster that already has more coordinators; retrying a previously successful scale request.","solutions":["Query the current partition count of system topic 'persistent://pulsar/system/transaction_coordinator_assign' and only call the scale endpoint when replicas > current count.","If the request is idempotent automation, treat HTTP 406 with this message as success (already at target count) rather than an error.","Downscaling is not supported by this API; if fewer coordinators are needed, follow the Pulsar docs/manual procedure or upgrade to a version that supports shrinking coordinators."],"exampleFix":"// before\nadmin.transactionCoordinators().scaleTransactionCoordinatorCount(4);\n\n// after\nint current = admin.namespaces().getPartitionedTopicMetadata(\n        \"persistent://pulsar/system/transaction_coordinator_assign\").partitions;\nif (4 > current) {\n    admin.transactionCoordinators().scaleTransactionCoordinatorCount(4);\n}","handlingStrategy":"validation","validationCode":"final PartitionedTopicMetadata md = admin\n    .namespaces()\n    .getPartitionedTopicMetadata(\"persistent://pulsar/system/transaction_coordinator_assign\")\n    .get();\nif (targetReplicas <= md.partitions) {\n    throw new IllegalArgumentException(\"replicas must be > current \" + md.partitions);\n}\nadmin.transactionCoordinators().scaleTransactionCoordinatorCount(targetReplicas);","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Make scale-up scripts idempotent: fetch current partition count first and no-op when equal to target.","Remember this API only scales up; never encode a shrink into the same call.","Treat HTTP 406 with this message as 'already at target' in automation."],"tags":["pulsar","admin-api","transactions","rest-exception","idempotency"],"backgroundTag":"invalid-scaling-request","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"}