apache/pulsar · error · RestException

Unauthorized to validateBothSuperuserAndClusterPolicyOperati

Error message

Unauthorized to validateBothSuperuserAndClusterPolicyOperation for originalPrincipal [${principal}] and clientAppId [${clientAppId}] about operation [${operation}] on cluster [${cluster}]

What it means

HTTP 401 (UNAUTHORIZED) thrown by validateBothSuperuserAndClusterPolicyOperation when the caller is neither a superuser nor authorized for the requested namespace-isolation policy operation on the cluster. This mirrors error 78 but for the policy sub-API: get/update cluster migration and all namespace-isolation policy read endpoints. The message names the principal, clientAppId, operation, and cluster.

Source

Thrown at pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/ClustersBase.java:1289

                    Throwable superUserValidationException = null;
                    try {
                        superUserAccessValidation.join();
                    } catch (Throwable ex) {
                        superUserValidationException = FutureUtil.unwrapCompletionException(ex);
                    }
                    Throwable clusterOperationValidationException = null;
                    try {
                        clusterOperationValidation.join();
                    } catch (Throwable ex) {
                        clusterOperationValidationException = FutureUtil.unwrapCompletionException(ex);
                    }
                    log.debug().attr("originalPrincipal", originalPrincipal())
                            .attr("operation", operation.toString())
                            .attr("cluster", clusterName)
                            .attr("superuserValidationError", superUserValidationException)
                            .attr("clusterOperationValidationError", clusterOperationValidationException)
                            .log("validateBothSuperuserAndClusterPolicyOperation failed");
                    throw new RestException(Status.UNAUTHORIZED,
                            String.format("Unauthorized to validateBothSuperuserAndClusterPolicyOperation for"
                                          + " originalPrincipal [%s] and clientAppId [%s] "
                                          + "about operation [%s] on cluster [%s]",
                                    originalPrincipal(), clientAppId(), operation.toString(), clusterName));
                });
    }

    private CompletableFuture<Void> validateClusterOperationAsync(String cluster, ClusterOperation operation) {
        final var pulsar = pulsar();
        if (pulsar.getBrokerService().isAuthenticationEnabled()
            && pulsar.getBrokerService().isAuthorizationEnabled()) {
            return pulsar.getBrokerService().getAuthorizationService()
                    .allowClusterOperationAsync(cluster, operation, originalPrincipal(),
                            clientAppId(), clientAuthData())
                    .thenAccept(isAuthorized -> {
                        if (!isAuthorized) {
                            throw new RestException(Status.UNAUTHORIZED,
                                    String.format("Unauthorized to validateClusterOperation for"

View on GitHub (pinned to 820761864e)

Solutions

  1. Use a superuser role, or grant the role the required cluster policy operation (e.g. read on namespace-isolation policies) via the configured authorization provider.
  2. Check that the token's role (clientAppId in the error) matches the intended admin role; re-issue the token if wrong.
  3. If operations run through a proxy, confirm originalPrincipal is preserved and authorized for policy operations.
  4. For read-only automation, create a dedicated role granted only the policy read operation.

Example fix

// before
PulsarAdmin admin = PulsarAdmin.builder()...token(readerToken).build();
admin.namespaces().getNamespaceIsolationPolicies("c1"); // 401
// after
PulsarAdmin admin = PulsarAdmin.builder()...token(adminToken).build(); // role authorized for policy ops
admin.namespaces().getNamespaceIsolationPolicies("c1");
Defensive patterns

Strategy: try-catch

Try / catch

try {
    Map<String, NamespaceIsolationData> policies =
            admin.namespaces().getNamespaceIsolationPolicies(cluster);
} catch (PulsarAdminException.NotAuthorizedException e) {
    // caller is not superuser and lacks policy-operation grant:
    // re-authenticate with an admin role or obtain the policy read permission
}

Prevention

When it happens

Trigger: GET /admin/v3/clusters/{cluster}/namespaceIsolationPolicies (and per-policy GET, brokersWithNamespaceIsolationPolicy, cluster migration GET/PUT) with a role lacking superuser status and lacking cluster policy operation grants.

Common situations: Tenant operators attempting to read isolation policies without global admin grants; token rotation replacing an admin token with a scoped user token; authorization provider changes dropping previously implicit read access.

Understand the failure class

Background: "You do not have permission" / 403 Forbidden errors: authenticated but not allowed — causes and fixes across open-source libraries — this error's family across 31 libraries.

Related errors


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