apache/pulsar · error · RestException
Client is not authorized to perform operation
Error message
Client is not authorized to perform operation
What it means
This error is thrown by the Functions Worker REST API when the underlying Pulsar admin client receives a PulsarAdminException.NotAuthorizedException while checking tenant/namespace permissions during source registration. The worker converts it into HTTP 401 UNAUTHORIZED, meaning the authenticated client lacks permissions to operate on the target tenant, not a malformed request.
Source
Thrown at pulsar-functions/worker/src/main/java/org/apache/pulsar/functions/worker/rest/api/SourcesImpl.java:126
String qualifiedNamespace = tenant + "/" + namespace;
List<String> namespaces = worker().getBrokerAdmin().namespaces().getNamespaces(tenant);
if (namespaces != null && !namespaces.contains(qualifiedNamespace)) {
String qualifiedNamespaceWithCluster = String.format("%s/%s/%s", tenant,
worker().getWorkerConfig().getPulsarFunctionsCluster(), namespace);
if (namespaces != null && !namespaces.contains(qualifiedNamespaceWithCluster)) {
log.error().attr("tenant", tenant).attr("namespace", namespace).attr("componentName", sourceName)
.attr("namespace3", namespace).log("/ / Namespace does not exist");
throw new RestException(Response.Status.BAD_REQUEST, "Namespace does not exist");
}
}
} catch (PulsarAdminException.NotAuthorizedException e) {
log.error().attr("tenant", tenant).attr("namespace", namespace).attr("componentName", sourceName)
.attr("componentType", ComponentTypeUtils.toString(componentType))
.log("/ / Client is not authorized to operate on tenant");
throw new RestException(Response.Status.UNAUTHORIZED, "Client is not authorized to perform operation");
} catch (PulsarAdminException.NotFoundException e) {
log.error().attr("tenant", tenant).attr("namespace", namespace).attr("componentName", sourceName)
.attr("tenant3", tenant).log("/ / Tenant does not exist");
throw new RestException(Response.Status.BAD_REQUEST, "Tenant does not exist");
} catch (PulsarAdminException e) {
log.error().attr("tenant", tenant).attr("namespace", namespace).attr("componentName", sourceName)
.exception(e).log("/ / Issues getting tenant data");
throw new RestException(Response.Status.INTERNAL_SERVER_ERROR, e.getMessage());
}
FunctionMetaDataManager functionMetaDataManager = worker().getFunctionMetaDataManager();
if (functionMetaDataManager.containsFunction(tenant, namespace, sourceName)) {
log.error().attr("componentType", ComponentTypeUtils.toString(componentType)).attr("tenant", tenant)
.attr("namespace", namespace).attr("componentName", sourceName).log("/ / already exists");View on GitHub (pinned to 820761864e)
Solutions
- Grant the client role permissions on the tenant/namespace: pulsar-admin namespaces grant-permissions <tenant>/<ns> --role <role> --actions produce,consume,functions
- Verify the client's auth credentials (auth plugin and parameters) are valid and identify the intended role
- Check broker authorizationProvider config and brokerClientAuthenticationPlugin on the worker so credentials are forwarded correctly
- Confirm you are targeting the correct tenant; a wrong tenant the role lacks rights on also yields 401
Example fix
// before (client without permissions) pulsar-admin sources create --tenant public --namespace default ... // -> 401 // after pulsar-admin namespaces grant-permissions public/default --role my-role --actions produce,consume pulsar-admin sources create --tenant public --namespace default ... // -> success
Defensive patterns
Strategy: try-catch
Validate before calling
// check role permissions before registering
try (PulsarAdmin admin = PulsarAdminClient.builder().serviceHttpUrl(adminUrl)
.authentication(AuthenticationFactory.token(token)).build()) {
Set<String> perms = admin.namespaces().getPermissions("public/default");
if (perms == null || !perms.contains("functions")) {
throw new IllegalStateException("role lacks functions permission on public/default");
}
} Type guard
boolean isAuthorized(Set<String> perms) {
return perms != null && (perms.contains("functions") || perms.contains("admin"));
} Try / catch
try {
sources.createSource(sourceConfig, pkgUrl, inputStream);
} catch (PulsarAdminException.NotAuthorizedException | javax.ws.rs.ClientErrorException e) {
if (((ClientErrorException) e).getResponse().getStatus() == 401) {
log.error("Not authorized for tenant {} — check role permissions", sourceConfig.getTenant(), e);
} else { throw e; }
} Prevention
- Provision role permissions (grant-permissions with functions/admin actions) as part of environment bootstrap
- Use the same role for tenant admin and source deployment in CI
- Verify auth plugin/token config on the client and that the worker forwards credentials
- Pin tenant/namespace names in one shared config to avoid targeting unknown tenants
When it happens
Trigger: Calling the registerSource REST endpoint (POST to the functions/sources API) when the client's role does not have produce/consume/admin permissions on the tenant or namespace hosting the source.
Common situations: Client configured with a role that lacks permissions in authorization.conf or the Pulsar permissions API; using the wrong tenant name; expired or misconfigured auth tokens/plugin in the client; broker authorization enabled but worker not forwarding client credentials.
Related errors
- This operation requires super-user access
- Unauthorized to validateClusterOperation for originalPrincip
- Unauthorized to validateClusterPolicyOperation for originalP
- Unauthorized to validateBothTenantOperationAndSuperUser for
- Time-out while checking authorization
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/4d377d55a1fac7ad.
Report an issue: GitHub.