apache/pulsar · warning · RestException
Unauthorized to validateTenantOperation for originalPrincipa
Error message
Unauthorized to validateTenantOperation for originalPrincipal [%s] and clientAppId [%s] about operation [%s] on tenant [%s]
What it means
HTTP 401 UNAUTHORIZED thrown by validateTenantOperationAsync: the authorization service denied the requested tenant-level operation for the originalPrincipal/clientAppId pair. The authenticated identity is not authorized to perform the tenant admin action (e.g. create namespace, list tenants under it).
Source
Thrown at pulsar-broker/src/main/java/org/apache/pulsar/broker/web/PulsarWebResource.java:1000
}
public void validateTenantOperation(String tenant, TenantOperation operation) {
sync(()-> validateTenantOperationAsync(tenant, operation));
}
public CompletableFuture<Void> validateTenantOperationAsync(String tenant, TenantOperation operation) {
if (pulsar().getConfiguration().isAuthenticationEnabled()
&& pulsar().getBrokerService().isAuthorizationEnabled()) {
if (!isClientAuthenticated(clientAppId())) {
return FutureUtil.failedFuture(
new RestException(Status.UNAUTHORIZED, "Need to authenticate to perform the request"));
}
return pulsar().getBrokerService().getAuthorizationService()
.allowTenantOperationAsync(tenant, operation, originalPrincipal(), clientAppId(), clientAuthData())
.thenAccept(isAuthorized -> {
if (!isAuthorized) {
throw new RestException(Status.UNAUTHORIZED,
String.format("Unauthorized to validateTenantOperation for"
+ " originalPrincipal [%s] and clientAppId [%s] "
+ "about operation [%s] on tenant [%s]",
originalPrincipal(), clientAppId(), operation.toString(), tenant));
}
});
}
return CompletableFuture.completedFuture(null);
}
public void validateNamespaceOperation(NamespaceName namespaceName, NamespaceOperation operation) {
sync(()-> validateNamespaceOperationAsync(namespaceName, operation));
}
public CompletableFuture<Void> validateNamespaceOperationAsync(NamespaceName namespaceName,
NamespaceOperation operation) {
if (pulsar().getConfiguration().isAuthenticationEnabled()
&& pulsar().getBrokerService().isAuthorizationEnabled()) {View on GitHub (pinned to 820761864e)
Solutions
- Add the role to the tenant's adminRoles: admin.tenants().updateTenant(tenant, TenantInfo with the role in adminRoles)
- Confirm originalPrincipal and clientAppId in the error/log match the intended identity and grant accordingly
- If operating through a proxy, ensure the proxy forwards the original principal and the broker's proxy-role trust config is correct
- Check the authorization provider implementation for extra constraints (e.g. pattern checks) being applied
Example fix
// before: caller not in tenant adminRoles
admin.tenants().createNamespace("my-tenant/ns1");
// after (as superuser)
Set<String> roles = new HashSet<>(tenantInfo.getAdminRoles());
roles.add("user-role");
admin.tenants().updateTenant("my-tenant", new TenantInfoImpl(roles, tenantInfo.getAllowedClusters())); Defensive patterns
Strategy: try-catch
Validate before calling
TenantInfo ti = admin.tenants().getTenantInfo(tenant);
if (!ti.getAdminRoles().contains(myRole)) throw new IllegalStateException("role not a tenant admin"); Try / catch
try {
tenantOp(tenant);
} catch (PulsarAdminException e) {
if (e.getStatusCode() == 401 && e.getMessage().contains("validateTenantOperation")) {
throw new SecurityException("request tenant adminRoles grant for role", e);
} else throw e;
} Prevention
- Add service accounts to tenant adminRoles at provisioning time
- Check originalPrincipal propagation when behind a proxy
- Re-grant after SSO/OIDC role remapping
When it happens
Trigger: Any admin API performing validateTenantOperation (tenant update, namespace creation in tenant, tenant policies) where allowTenantOperationAsync returns false for the caller's role.
Common situations: User lacks the tenant admin role (tenant's adminRoles); proxy forwarded originalPrincipal not granted tenant access; keycloak/OIDC role mapping changed; app id restricted by authorization provider policy.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
- Don't have permission to administrate resources on this tena
- Unauthorized to validateBothSuperuserAndBrokerOperation for
- Unauthorized to validateBrokerOperation for originalPrincipa
- Unauthorized to validateBothTenantOperationAndSuperUser for
- Proxy not authorized to access resource (proxy:%s,original:%
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/fa9496bc710f74e6.
Report an issue: GitHub.