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
- Perform the write operation on a broker/cluster whose configuration store is writable (the correct administrative cluster).
- Change broker configuration so the policies store is writable (point configurationStore/policies to a writable store and remove read-only mode), then restart brokers.
- If the read-only state is stale, fix the underlying policies read-only flag in the configuration store.
- 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
- Point admin tooling at the cluster with a writable configuration store
- Track which brokers are read-only in deployment config and gate writes in scripts
- After failover, re-point admin clients before running mutations
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
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Invalid broker configuration. Authentication must be enabled
- Cluster ${cluster} does not exist.
- Unauthorized to validateBothSuperuserAndBrokerOperation for
- No authorization providers are present.
- Invalid proxy configuration. Authentication must be enabled
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/d32c2ad5c247d244.
Report an issue: GitHub.