apache/pulsar · error · org.apache.pulsar.broker.admin.RestException

Broker is forbidden to do read-write operations

Error message

Broker is forbidden to do read-write operations

What it means

When a broker is configured with read-only policies (e.g. the cluster is in a read-only/migrating state where namespace policies are marked read-only), AdminResource.validatePoliciesReadOnlyAccessAsync rejects any mutating admin operation with HTTP 403 'Broker is forbidden to do read-write operations'. This protects a broker whose policy store must not be modified (commonly during center/global policy synchronization setups).

Source

Thrown at pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/AdminResource.java:149

     * @throws WebApplicationException
     *             if broker has a read only access if broker is not connected to the configuration metadata-store
     */

    public void validatePoliciesReadOnlyAccess() {
        try {
            validatePoliciesReadOnlyAccessAsync().join();
        } catch (CompletionException ce) {
            throw new RestException(ce.getCause());
        }
    }

    public CompletableFuture<Void> validatePoliciesReadOnlyAccessAsync() {

        return pulsar().getPulsarResources().getNamespaceResources().getPoliciesReadOnlyAsync()
                .thenAccept(arePoliciesReadOnly -> {
                    if (arePoliciesReadOnly) {
                            log.debug("Policies are read-only. Broker cannot do read-write operations");
                                                throw new RestException(Status.FORBIDDEN,
                                                        "Broker is forbidden to do read-write operations");
                    } else {
                        // Do nothing, just log the message.
                            log.debug("Broker is allowed to make read-write operations");
                                            }
                });
    }

    protected CompletableFuture<Void> tryCreatePartitionsAsync(int numPartitions) {
        if (!topicName.isPersistent()) {
            for (int i = 0; i < numPartitions; i++) {
                pulsar().getBrokerService().getTopicEventsDispatcher()
                        .notify(topicName.getPartition(i).toString(), TopicEvent.CREATE, EventStage.SUCCESS);
            }
            return CompletableFuture.completedFuture(null);
        }
        List<CompletableFuture<Void>> futures = new ArrayList<>(numPartitions);
        for (int i = 0; i < numPartitions; i++) {

View on GitHub (pinned to 820761864e)

Solutions

  1. Perform the write operation on a broker/cluster whose configuration store is writable (the correct administrative cluster).
  2. Change broker configuration so the policies store is writable (point configurationStore/policies to a writable store and remove read-only mode), then restart brokers.
  3. If the read-only state is stale, fix the underlying policies read-only flag in the configuration store.
  4. For read-only deployments, use the designated management endpoint rather than this broker.

Example fix

// before (broker.conf)
configurationStore=zk1:2181/global-readonly
# broker cannot write policies

// after (broker.conf)
configurationStore=zk-admin:2181/global
# writable configuration store; restart brokers
Defensive patterns

Strategy: try-catch

Validate before calling

// Check cluster writability before admin writes
boolean readOnly = admin.namespaces().getPolicies(tenant + "/" + ns) != null
        && brokerConfig.isConfigurationStoreReadOnly(); // from your deployment config
if (readOnly) throw new IllegalStateException("Broker policies are read-only; perform writes elsewhere");

Try / catch

try {
    admin.namespaces().createNamespace(ns);
} catch (PulsarAdminException e) {
    if (e.getStatusCode() == 403 && e.getMessage().contains("read-write operations")) {
        log.error("Broker is in read-only policies mode; run admin ops against the writable cluster");
    }
}

Prevention

When it happens

Trigger: Any write admin API call (create/update namespace policies, set permissions, etc.) while the namespace policies are flagged read-only in the local policy store (policiesReadOnly), typically when the broker reads policies from a global/read-only configuration store.

Common situations: Clusters configured with a read-only global zookeeper/configuration store (e.g. geo-replication control plane setups); operating against a broker intended only to serve, not administer; running admin scripts against the wrong cluster after a failover.

Understand the failure class

Related errors


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