{"record":{"id":"c5a8dda0c5a0b973","repo":"apache/pulsar","slug":"unauthorized-to-validatebothsuperuserandclusterpol","errorCode":null,"errorMessage":"Unauthorized to validateBothSuperuserAndClusterPolicyOperation for originalPrincipal [${principal}] and clientAppId [${clientAppId}] about operation [${operation}] on cluster [${cluster}]","messagePattern":"Unauthorized to validateBothSuperuserAndClusterPolicyOperation for originalPrincipal \\[(.+?)\\] and clientAppId \\[(.+?)\\] about operation \\[(.+?)\\] on cluster \\[(.+?)\\]","errorType":"http","errorClass":"RestException","httpStatus":401,"severity":"error","filePath":"pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/ClustersBase.java","lineNumber":1289,"sourceCode":"                    Throwable superUserValidationException = null;\n                    try {\n                        superUserAccessValidation.join();\n                    } catch (Throwable ex) {\n                        superUserValidationException = FutureUtil.unwrapCompletionException(ex);\n                    }\n                    Throwable clusterOperationValidationException = null;\n                    try {\n                        clusterOperationValidation.join();\n                    } catch (Throwable ex) {\n                        clusterOperationValidationException = FutureUtil.unwrapCompletionException(ex);\n                    }\n                    log.debug().attr(\"originalPrincipal\", originalPrincipal())\n                            .attr(\"operation\", operation.toString())\n                            .attr(\"cluster\", clusterName)\n                            .attr(\"superuserValidationError\", superUserValidationException)\n                            .attr(\"clusterOperationValidationError\", clusterOperationValidationException)\n                            .log(\"validateBothSuperuserAndClusterPolicyOperation failed\");\n                    throw new RestException(Status.UNAUTHORIZED,\n                            String.format(\"Unauthorized to validateBothSuperuserAndClusterPolicyOperation for\"\n                                          + \" originalPrincipal [%s] and clientAppId [%s] \"\n                                          + \"about operation [%s] on cluster [%s]\",\n                                    originalPrincipal(), clientAppId(), operation.toString(), clusterName));\n                });\n    }\n\n    private CompletableFuture<Void> validateClusterOperationAsync(String cluster, ClusterOperation operation) {\n        final var pulsar = pulsar();\n        if (pulsar.getBrokerService().isAuthenticationEnabled()\n            && pulsar.getBrokerService().isAuthorizationEnabled()) {\n            return pulsar.getBrokerService().getAuthorizationService()\n                    .allowClusterOperationAsync(cluster, operation, originalPrincipal(),\n                            clientAppId(), clientAuthData())\n                    .thenAccept(isAuthorized -> {\n                        if (!isAuthorized) {\n                            throw new RestException(Status.UNAUTHORIZED,\n                                    String.format(\"Unauthorized to validateClusterOperation for\"","sourceCodeStart":1271,"sourceCodeEnd":1307,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-broker/src/main/java/org/apache/pulsar/broker/admin/impl/ClustersBase.java#L1271-L1307","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["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.","Check that the token's role (clientAppId in the error) matches the intended admin role; re-issue the token if wrong.","If operations run through a proxy, confirm originalPrincipal is preserved and authorized for policy operations.","For read-only automation, create a dedicated role granted only the policy read operation."],"exampleFix":"// before\nPulsarAdmin admin = PulsarAdmin.builder()...token(readerToken).build();\nadmin.namespaces().getNamespaceIsolationPolicies(\"c1\"); // 401\n// after\nPulsarAdmin admin = PulsarAdmin.builder()...token(adminToken).build(); // role authorized for policy ops\nadmin.namespaces().getNamespaceIsolationPolicies(\"c1\");","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n    Map<String, NamespaceIsolationData> policies =\n            admin.namespaces().getNamespaceIsolationPolicies(cluster);\n} catch (PulsarAdminException.NotAuthorizedException e) {\n    // caller is not superuser and lacks policy-operation grant:\n    // re-authenticate with an admin role or obtain the policy read permission\n}","preventionTips":["Use admin credentials for namespace-isolation policy reads; tenant-scoped roles are typically insufficient.","After token rotation, re-verify the new token's role has policy operation grants.","For read-only tooling, request a dedicated role granted only the needed policy read operation."],"tags":["authorization","unauthorized","isolation-policy","security"],"backgroundTag":"insufficient-permissions","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"}